diff --git a/.github/workflows/gh_pages.yml b/.github/workflows/gh_pages.yml index bdce044da..36413e885 100644 --- a/.github/workflows/gh_pages.yml +++ b/.github/workflows/gh_pages.yml @@ -1,4 +1,4 @@ -name: Deploy documentation to GH Pages +name: Deploy to GH Pages on: workflow_dispatch: @@ -6,7 +6,7 @@ on: branches: [main] jobs: - build: + build-documentation: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -19,9 +19,9 @@ jobs: # deploys the result of `build` # this job is a copy paste from - deploy: + deploy-documentation: # Add a dependency to the build job - needs: build + needs: build-documentation # Grant GITHUB_TOKEN the permissions required to make a Pages deployment permissions: @@ -39,3 +39,74 @@ jobs: - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@v2 # or the latest "vX.X.X" version tag for this action + + # Builds and deploy "external" GH pages: pushes to the repos + # `hacspec/hacspec.github.io` and `hacspec/book` + build-and-deploy-external-gh-pages: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + path: hax + - uses: actions/checkout@v4 + with: + repository: "hacspec/hacspec.github.io" + path: hacspec.github.io + token: ${{secrets.PUSH_HACSPEC_GITHUB_TOKEN}} + - uses: actions/checkout@v4 + with: + repository: "hacspec/book" + path: book + token: ${{secrets.PUSH_HACSPEC_GITHUB_TOKEN}} + + - uses: DeterminateSystems/nix-installer-action@main + + - name: Configure git + run: | + git config --global user.name "github-actions[bot]" + git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com" + + - name: Patch and push `README.md` in `hacspec.github.io` + run: | + ( + README_ORIGINAL="https://github.com/hacspec/hax/blob/main/README.md" + echo "" + echo "" + cat hax/README.md + ) > hacspec.github.io/README.md + cd hacspec.github.io + + # Replace the `🌐 Website` link to a GitHub link + sed -i 's#.*🌐 Website.*# 🔗 GitHub |#' README.md + + # Replace relative links to absolute links + sed -i 's|(\./|(https://github.com/hacspec/hax/tree/main/|g' README.md + + git add -A + if git commit -m "Readme update"; then + git push https://$USERNAME:$PUSH_HACSPEC_GITHUB_TOKEN@github.com/hacspec/hacspec.github.io + fi + + - name: Regenerate and push the book + run: | + nix build ./hax#hax-book -o result-hax-book + HAX_COMMIT=$(git -C ./hax rev-parse --short HEAD) + + mkdir hax-book + rsync -rq --no-perms --chown=$(id -un):$(id -gn) "$(realpath result-hax-book)/" hax-book + mv book/.git hax-book/.git + cd hax-book + + { + echo "# Warning: this repository only contains generated files" + echo "The sources of the book are in https://github.com/hacspec/hax/tree/main/book" + echo "Please file issues, and push PRs to https://github.com/hacspec/hax." + } > README.md + + git add -A + if git commit -m "Book update (generated from hacspec/hax@$HAX_COMMIT)"; then + git push https://$USERNAME:$PUSH_HACSPEC_GITHUB_TOKEN@github.com/hacspec/book + fi + env: + PUSH_HACSPEC_GITHUB_TOKEN: ${{secrets.PUSH_HACSPEC_GITHUB_TOKEN}} + USERNAME: github-actions[bot] diff --git a/.github/workflows/install_and_test.yml b/.github/workflows/install_and_test.yml index 153175e83..67a34828c 100644 --- a/.github/workflows/install_and_test.yml +++ b/.github/workflows/install_and_test.yml @@ -14,6 +14,10 @@ jobs: steps: - uses: actions/checkout@v3 - uses: DeterminateSystems/nix-installer-action@main + - uses: cachix/cachix-action@v15 + with: + name: hax + skipPush: true - uses: DeterminateSystems/magic-nix-cache-action@main - name: Build run: nix build -L @@ -47,7 +51,6 @@ jobs: env: CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }} run: | - nix profile install nixpkgs#cachix nixpkgs#jq nix build .# .#fstar --json \ | jq -r '.[].outputs | to_entries[].value' \ | cachix push hax diff --git a/.github/workflows/kyber.yml b/.github/workflows/mlkem.yml similarity index 98% rename from .github/workflows/kyber.yml rename to .github/workflows/mlkem.yml index 729317785..267e1e9e5 100644 --- a/.github/workflows/kyber.yml +++ b/.github/workflows/mlkem.yml @@ -1,4 +1,4 @@ -name: Extract and TC Kyber +name: Extract and TC ML-Kem on: pull_request: @@ -11,7 +11,7 @@ env: CARGO_TERM_COLOR: always jobs: - hax: + extract-mlkem: if: ${{ github.event_name == 'workflow_dispatch' || github.event_name == 'merge_group' }} runs-on: "ubuntu-latest" diff --git a/.github/workflows/push_readme.yml b/.github/workflows/push_readme.yml deleted file mode 100644 index d4b17ec0e..000000000 --- a/.github/workflows/push_readme.yml +++ /dev/null @@ -1,43 +0,0 @@ -name: Push `README.md` - -on: - push: - branches: [main] - -jobs: - push_readme: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - path: hax - - uses: actions/checkout@v4 - with: - repository: "hacspec/hacspec.github.io" - path: website - token: ${{secrets.PUSH_HACSPEC_GITHUB_TOKEN}} - - name: Publish documentation - run: | - ( - README_ORIGINAL="https://github.com/hacspec/hax/blob/main/README.md" - echo "" - echo "" - cat hax/README.md - ) > website/README.md - cd website - - # Replace the `🌐 Website` link to a GitHub link - sed -i 's#.*🌐 Website.*# 🔗 GitHub |#' README.md - - # Replace relative links to absolute links - sed -i 's|(\./|(https://github.com/hacspec/hax/tree/main/|g' README.md - - git config --local user.name "github-actions[bot]" - git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add -A - if git commit -m "Readme update"; then - git push https://$USERNAME:$PUSH_HACSPEC_GITHUB_TOKEN@github.com/hacspec/hacspec.github.io - fi - env: - PUSH_HACSPEC_GITHUB_TOKEN: ${{secrets.PUSH_HACSPEC_GITHUB_TOKEN}} - USERNAME: github-actions[bot] diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 000000000..c7347c48f --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,22 @@ +name: 'Triage stale issues and PRs' +on: + schedule: + - cron: '00 1 * * *' + workflow_dispatch: + +jobs: + stale: + runs-on: ubuntu-latest + steps: + - uses: actions/stale@v9 + with: + stale-issue-message: "This issue has been marked as stale due to a lack of activity for 60 days. If you believe this issue is still relevant, please provide an update or comment to keep it open. Otherwise, it will be closed in 7 days." + stale-pr-message: "This PR has been marked as stale due to a lack of activity for 60 days. If you believe this pull request is still relevant, please provide an update or comment to keep it open. Otherwise, it will be closed in 7 days." + stale-issue-label: 'stale' + exempt-issue-labels: 'keep-open' + stale-pr-label: 'stale' + exempt-pr-labels: 'keep-open' + days-before-stale: 60 + days-before-close: 7 + close-issue-message: "This issue has been closed due to a lack of activity since being marked as stale. If you believe this issue is still relevant, please reopen it with an update or comment." + close-pr-message: "This PR has been closed due to a lack of activity since being marked as stale. If you believe this pull request is still relevant, please reopen it with an update or comment." diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e1d7ed9aa..fbf6273b5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -30,6 +30,9 @@ jobs: - name: Test run: cargo test --workspace --exclude hax-engine-names-extract --verbose + - name: Test `hax-frontend-exporter` with feature `rustc` off + run: cargo check -p hax-frontend-exporter --no-default-features --verbose + no-std-lib: runs-on: ubuntu-latest steps: diff --git a/.github/workflows/test_installs.yml b/.github/workflows/test_installs.yml index f0de760ea..f7dc327e9 100644 --- a/.github/workflows/test_installs.yml +++ b/.github/workflows/test_installs.yml @@ -22,7 +22,7 @@ jobs: - ubuntu-latest - ubuntu-20.04 - macos-latest - - macos-11 + - macos-12 runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v3 diff --git a/.utils/list-names.sh b/.utils/list-names.sh new file mode 100755 index 000000000..e0c99c586 --- /dev/null +++ b/.utils/list-names.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +function pager() { + if command -v bat &> /dev/null; then + bat -l ml + else + less + fi +} + +hax-engine-names-extract | sed '/include .val/,$d' | pager diff --git a/.utils/rebuild.sh b/.utils/rebuild.sh index 3d78ac471..adadc61ce 100755 --- a/.utils/rebuild.sh +++ b/.utils/rebuild.sh @@ -23,7 +23,7 @@ YELLOW=43 GREEN=42 RED=41 BLACK=40 -status () { echo -e "\e[1m[rebuild script] \e[30m\e[$1m$2\e[0m"; } +status () { echo -e "\033[1m[rebuild script] \033[30m\033[$1m$2\033[0m"; } cd_rootwise () { cd $(git rev-parse --show-toplevel)/$1 diff --git a/Cargo.lock b/Cargo.lock index 4f332a8ad..2e1015863 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,6 +11,16 @@ dependencies = [ "memchr", ] +[[package]] +name = "annotate-snippets" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24e35ed54e5ea7997c14ed4c70ba043478db1112e98263b3b035907aa197d991" +dependencies = [ + "anstyle", + "unicode-width", +] + [[package]] name = "anstream" version = "0.6.4" @@ -86,6 +96,25 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "bincode" +version = "2.0.0-rc.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f11ea1a0346b94ef188834a65c068a03aec181c94896d481d7a0a40d85b0ce95" +dependencies = [ + "bincode_derive", + "serde", +] + +[[package]] +name = "bincode_derive" +version = "2.0.0-rc.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e30759b3b99a1b802a7a3aa21c85c3ded5c28e1c83170d82d70f08bbf7f3e4c" +dependencies = [ + "virtue", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -128,22 +157,28 @@ dependencies = [ name = "cargo-hax" version = "0.1.0-pre.1" dependencies = [ + "annotate-snippets", + "cargo_metadata", "clap", "colored", - "hax-cli-options", - "hax-cli-options-engine", - "hax-diagnostics", + "extension-traits", "hax-frontend-exporter", "hax-frontend-exporter-options", "hax-lib-macros-types", + "hax-phase-debug-webapp", + "hax-types", + "inquire", "is-terminal", "itertools", "paste", "path-clean", + "prettyplease", "rustup-toolchain", "schemars", "serde", + "serde-jsonlines", "serde_json", + "syn 2.0.68", "tempfile", "toml 0.8.3", "version_check", @@ -175,12 +210,13 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.83" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +checksum = "779e6b7d17797c0b42023d417228c02889300190e700cb074c3438d9c541d332" dependencies = [ "jobserver", "libc", + "once_cell", ] [[package]] @@ -226,7 +262,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.68", ] [[package]] @@ -264,26 +300,6 @@ dependencies = [ "windows-sys 0.45.0", ] -[[package]] -name = "const_format" -version = "0.2.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3a214c7af3d04997541b18d432afaff4c455e79e2029079647e72fc2bd27673" -dependencies = [ - "const_format_proc_macros", -] - -[[package]] -name = "const_format_proc_macros" -version = "0.2.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7f6ff08fd20f4f299298a28e2dfa8a8ba1036e6cd2460ac1de7b425d76f2500" -dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", -] - [[package]] name = "crossterm" version = "0.25.0" @@ -321,6 +337,16 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" +[[package]] +name = "duplicate" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de78e66ac9061e030587b2a2e75cc88f22304913c907b11307bca737141230cb" +dependencies = [ + "heck", + "proc-macro-error", +] + [[package]] name = "dyn-clone" version = "1.0.14" @@ -356,7 +382,7 @@ checksum = "eecf8589574ce9b895052fa12d69af7a233f99e6107f5cb8dd1044f2a17bfdcb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.68", ] [[package]] @@ -444,44 +470,9 @@ dependencies = [ name = "hax-bounded-integers" version = "0.1.0-pre.1" dependencies = [ + "duplicate", "hax-lib", -] - -[[package]] -name = "hax-cli-options" -version = "0.1.0-pre.1" -dependencies = [ - "clap", - "hax-frontend-exporter-options", - "path-clean", - "schemars", - "serde", - "serde_json", -] - -[[package]] -name = "hax-cli-options-engine" -version = "0.1.0-pre.1" -dependencies = [ - "clap", - "hax-cli-options", - "hax-diagnostics", - "hax-frontend-exporter", - "hax-frontend-exporter-options", - "itertools", - "path-clean", - "schemars", - "serde", - "serde_json", -] - -[[package]] -name = "hax-diagnostics" -version = "0.1.0-pre.1" -dependencies = [ - "colored", - "schemars", - "serde", + "paste", ] [[package]] @@ -490,23 +481,16 @@ version = "0.1.0-pre.1" dependencies = [ "clap", "colored", - "const_format", - "hax-cli-options", - "hax-cli-options-engine", - "hax-diagnostics", "hax-frontend-exporter", "hax-frontend-exporter-options", "hax-lib-macros-types", - "hax-lint", - "hax-phase-debug-webapp", - "inquire", + "hax-types", "itertools", "serde", "serde_json", "tracing", "tracing-subscriber", "tracing-tree", - "which", ] [[package]] @@ -521,9 +505,8 @@ dependencies = [ name = "hax-engine-names-extract" version = "0.1.0-pre.1" dependencies = [ - "camino", - "cargo_metadata", - "hax-cli-options-engine", + "bincode", + "hax-adt-into", "hax-engine-names", "serde", "serde_json", @@ -534,6 +517,7 @@ dependencies = [ name = "hax-frontend-exporter" version = "0.1.0-pre.1" dependencies = [ + "bincode", "extension-traits", "hax-adt-into", "hax-frontend-exporter-options", @@ -550,6 +534,8 @@ dependencies = [ name = "hax-frontend-exporter-options" version = "0.1.0-pre.1" dependencies = [ + "bincode", + "hax-adt-into", "schemars", "serde", "serde_json", @@ -570,10 +556,11 @@ version = "0.1.0-pre.1" dependencies = [ "hax-lib", "hax-lib-macros-types", + "paste", "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.68", ] [[package]] @@ -602,18 +589,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.38", -] - -[[package]] -name = "hax-lint" -version = "0.1.0-pre.1" -dependencies = [ - "assert_cmd", - "hax-diagnostics", - "lazy_static", - "regex", - "tracing", + "syn 2.0.68", ] [[package]] @@ -630,7 +606,7 @@ dependencies = [ "assert_cmd", "cargo_metadata", "enum-iterator", - "hax-cli-options-engine", + "hax-types", "insta", "lazy_static", "libtest-mimic", @@ -639,6 +615,25 @@ dependencies = [ "serde_json", ] +[[package]] +name = "hax-types" +version = "0.1.0-pre.1" +dependencies = [ + "annotate-snippets", + "bincode", + "clap", + "colored", + "hax-adt-into", + "hax-frontend-exporter", + "hax-frontend-exporter-options", + "itertools", + "path-clean", + "schemars", + "serde", + "serde_json", + "zstd", +] + [[package]] name = "heck" version = "0.4.1" @@ -736,9 +731,9 @@ checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "jobserver" -version = "0.1.27" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" +checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" dependencies = [ "libc", ] @@ -931,9 +926,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "overload" @@ -966,9 +961,9 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "path-clean" @@ -982,6 +977,12 @@ version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -1016,6 +1017,16 @@ dependencies = [ "termtree", ] +[[package]] +name = "prettyplease" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" +dependencies = [ + "proc-macro2", + "syn 2.0.68", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -1042,18 +1053,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.69" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.33" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -1217,6 +1228,16 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-jsonlines" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e228faf5f94badfe42723177b62cfb9b187351994cb4e852cd4a6a4c96dbeea8" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "serde_derive" version = "1.0.189" @@ -1225,7 +1246,7 @@ checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.68", ] [[package]] @@ -1329,9 +1350,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.38" +version = "2.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" +checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9" dependencies = [ "proc-macro2", "quote", @@ -1368,22 +1389,22 @@ checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" [[package]] name = "thiserror" -version = "1.0.50" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.50" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.68", ] [[package]] @@ -1479,7 +1500,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.68", ] [[package]] @@ -1551,12 +1572,6 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" -[[package]] -name = "unicode-xid" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" - [[package]] name = "utf8parse" version = "0.2.1" @@ -1584,6 +1599,12 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "virtue" +version = "0.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dcc60c0624df774c82a0ef104151231d37da4962957d691c011c852b2473314" + [[package]] name = "wait-timeout" version = "0.2.0" @@ -1620,7 +1641,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.68", "wasm-bindgen-shared", ] @@ -1642,7 +1663,7 @@ checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.68", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -1911,3 +1932,31 @@ checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" dependencies = [ "linked-hash-map", ] + +[[package]] +name = "zstd" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d789b1514203a1120ad2429eae43a7bd32b90976a7bb8a05f7ec02fa88cc23a" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd99b45c6bc03a018c8b8a86025678c87e55526064e38f9df301989dce7ec0a" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.11+zstd.1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75652c55c0b6f3e6f12eb786fe1bc960396bf05a1eb3bf1f3691c3610ac2e6d4" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/Cargo.toml b/Cargo.toml index 6ed486c11..5e17ffda4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,10 +2,6 @@ members = [ "frontend/exporter", "frontend/exporter/options", - "frontend/diagnostics", - "frontend/lint", - "cli/options", - "cli/options/engine", "cli/subcommands", "cli/driver", "test-harness", @@ -18,15 +14,12 @@ members = [ "hax-bounded-integers", "engine/names", "engine/names/extract", + "hax-types", ] exclude = ["tests"] default-members = [ "frontend/exporter", "frontend/exporter/options", - "frontend/diagnostics", - "frontend/lint", - "cli/options", - "cli/options/engine", "cli/subcommands", "cli/driver", "test-harness", @@ -77,17 +70,16 @@ quote = "1.0.32" proc-macro2 = "1.0.66" cargo_metadata = "0.15" colored = "2" +bincode = "2.0.0-rc.3" +annotate-snippets = "0.11" # Crates in this repository -hax-frontend-exporter = { path = "frontend/exporter", version = "=0.1.0-pre.1" } +hax-frontend-exporter = { path = "frontend/exporter", version = "=0.1.0-pre.1", default-features = false } hax-adt-into = { path = "frontend/exporter/adt-into", version = "=0.1.0-pre.1" } -hax-cli-options = { path = "cli/options", version = "=0.1.0-pre.1" } -hax-cli-options-engine = { path = "cli/options/engine", version = "=0.1.0-pre.1" } hax-frontend-exporter-options = { path = "frontend/exporter/options", version = "=0.1.0-pre.1" } -hax-diagnostics = { path = "frontend/diagnostics", version = "=0.1.0-pre.1" } -hax-lint = { path = "frontend/lint", version = "=0.1.0-pre.1" } hax-phase-debug-webapp = { path = "engine/utils/phase-debug-webapp", version = "=0.1.0-pre.1" } hax-lib-macros-types = { path = "hax-lib-macros/types", version = "=0.1.0-pre.1" } hax-lib-macros = { path = "hax-lib-macros", version = "=0.1.0-pre.1" } hax-lib = { path = "hax-lib", version = "=0.1.0-pre.1" } hax-engine-names = { path = "engine/names", version = "=0.1.0-pre.1" } +hax-types = { path = "hax-types", version = "=0.1.0-pre.1" } diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..9b7b24ebd --- /dev/null +++ b/LICENSE @@ -0,0 +1,191 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2023 Hax Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/PUBLISHING.md b/PUBLISHING.md index f8e46e624..ae1491466 100644 --- a/PUBLISHING.md +++ b/PUBLISHING.md @@ -14,10 +14,8 @@ and `examples`): 1. `hax-frontend-exporter-options` (`frontend/exporter/options `) 2. `hax-adt-into` (`frontend/exporter/adt-into`) 3. `hax-frontend-exporter` (`frontend/exporter`) -4. `hax-cli-options` (`cli/options`) -5. `hax-diagnostics` (`frontend/diagnostics`) -6. `hax-cli-options-engine` (`cli/options/engine`) -7. `hax-subcommands` (binaries) (`cli/subcommands`) +4. `hax-types` (`hax-types`) +5. `hax-subcommands` (binaries) (`cli/subcommands`) - `cargo-hax` - `hax-export-json-schemas` - `hax-pretty-print-diagnostics` diff --git a/README.md b/README.md index b5bbfc400..06d297e42 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,14 @@ +

+ +

+

🌐 Website | 📖 Book | 📝 Blog | 💬 Zulip | - 🛠️ Internal docs + 🛠️ Internal docs | + 🛝 Playground

# Hax @@ -20,6 +25,12 @@ standard library, to write succinct, executable, and verifiable specifications i Rust. These specifications can be translated into formal languages with hax. +

+ + Try out hax online now! + +

+ ## Learn more Here are some resources for learning more about hax: diff --git a/book/.gitignore b/book/.gitignore new file mode 100644 index 000000000..05ff2e452 --- /dev/null +++ b/book/.gitignore @@ -0,0 +1,2 @@ +book +target diff --git a/book/archive/book.toml b/book/archive/book.toml new file mode 100644 index 000000000..530d58507 --- /dev/null +++ b/book/archive/book.toml @@ -0,0 +1,9 @@ +[book] +authors = ["Franziskus Kiefer"] +language = "en" +multilingual = false +src = "src" +title = "hacspec" + +[output.html] +mathjax-support = true diff --git a/book/archive/src/SUMMARY.md b/book/archive/src/SUMMARY.md new file mode 100644 index 000000000..6ff0d4f43 --- /dev/null +++ b/book/archive/src/SUMMARY.md @@ -0,0 +1,22 @@ +# Summary + +- [Introduction](./readme.md) +- [The hacspec language](./language/readme.md) + - [Syntax](./language/syntax.md) + - [Core](./language/core.md) + - [Sequences and arrays](./language/seq.md) + - [Structs and enums](./language/enums.md) + - [Error handling](./language/errors.md) +- [The hacspec std library](./std/readme.md) + - [Arithmetic](./std/arithmetic.md) + - [Sequence and array operations](./std/seq.md) +- [Examples](./examples/readme.md) +- [Usage](./usage/readme.md) + - [Specifications](./usage/specifications.md) + - [Verification](./usage/verification.md) + - [Test Vectors](./usage/test_vectors.md) +- [For Developers](./developers/readme.md) + - [Working on the compiler](./developers/compiler.md) + +--- +[Contributors](misc/contributors.md) diff --git a/book/archive/src/developers/compiler.md b/book/archive/src/developers/compiler.md new file mode 100644 index 000000000..48a8dde17 --- /dev/null +++ b/book/archive/src/developers/compiler.md @@ -0,0 +1,152 @@ +# Working on the compiler + +## High-level architecture + +![Hacspec compiler architecture](hacspec_architecture.png) + +The Rustspec compiler intervenes after the regular Rust typechecking, +by translating the Rust AST into a stricter hacspec AST, +yielding error messages if you're not in the subset. + +The hacspec AST then undergoes a typechecking phase that replicates the +formal typechecking judgment of hacspec, before being compiled +to the proof backends like F* or Coq. + +## Code organization + +The source code for the compiler is located in the `language/` folder. +`main.rs` is the file containing the driver for the different compiler +passes. + +### Hacspec AST + +The main file of the compiler is `rustspec.rs` and it contains the AST +structure. + +Types are usually enclosed into `Spanned<...>` blocks that attach a location +information to an AST node, thereby providing a way to display beautiful error +message. + +Several nodes also contain a `Fillable<...>` node standing for information +that is filled by the typechecking phase but that can be left to `None` when +building the AST. + +### Translation from Rust AST + +This phase is contained in `ast_to_rustspec.rs`. The trickyness of this +translation is that it needs to be aware of certain special names contained +in the structure `SpecialNames`. Indeed, while the Rust AST treats the application +enum constructors like function applications, the hacspec AST considers them as +proper injection so we need to distinguish them in the Rust AST. For that, we +need to know all declared enums at this point of the program. + +Enums and other `SpecialNames` are also defined in the `ExternalData` that +contains the signatures and types imported in crates used by the hacspec +program being compiled. + +### Name resolution + +When the translation from Rust AST is finished, the identifiers for all +variables inside function bodies are of the following type: + +```rust, noplaypen +pub enum Ident { + Unresolved(String), + Local(LocalIdent), + TopLevel(TopLevelIdent), +} +``` + +More precisely, they are still in the `Ident::Unresolved` case. The compiler +pass in `name_resolution.rs` resolves the identifiers by linking them to local or global identifiers, +each one having a unique ID. hacspec does not feature De Bruijn variable +handling, instead relying on unique fresh IDs for differentiating local +and global variables from each other. + +### External data + +A hacspec file can never (in principal) be considered alone, as it usually imports +at least several other crates like the hacspec standard library. These external +crates must pre-populate the typechecking context with the types and function +signatures that they define. + +It's the job of `hir_to_rustspec.rs` to retrieve this data. The critical +piece of code in this file is [the following](https://github.com/hacspec/hacspec/blob/cc609254b0aa978646f494291b9c91a92fe107ee/language/src/hir_to_rustspec.rs#L733-L737): + +```rust, noplaypen +let num_def_ids = crate_store.num_def_ids_untracked(*krate_num); +let def_ids = (0..num_def_ids).into_iter().map(|id| DefId { + krate: *krate_num, + index: DefIndex::from_usize(id), +}); +``` + +First, we retrieve the number of exported symbols by an external crate using +`num_def_ids_untracked`, a function that is [specifically labeled](https://github.com/rust-lang/rust/pull/85889) +as critical to the hacspec compiler in the Rust compiler codebase. Then, +we manufacture definition IDs for all these exported symbols, relying on the +invariant that they are numbered from 0 to the number of exported symbols +in Rust's compiled crate metadata format. + +Then, we use those definition IDs (`DefId`) to query the Rust compiler +via the central [`TyCtxt`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html) +data structure. If the `DefId` corresponds to a type definition, we examine the +type definition structurally and check whether it corresponds to a hacspec-compatible +type definition. Notably, the type definitions generated by macros like `array!` +or `nat_mod!` are only seen here in their expanded version, so we have to retro-engineer +which expanded version corresponds to which macro expansion. This is a vulnerability +of the compiler since it's possible to break the abstraction of the language +by smuggling in a type not defined via a hacspec macro this way. That's why hacspec +developers should be very careful about which dependencies they import in order +to have a 100% safety guarantee. + +For `DefId`s corresponding to functions, the signature of the function is analysed +and if it fits the subset of types expected by hacspec, the function is imported +along with its type in a pre-populated typechecking context. + +Note that it is not possible any more at this point to retrieve the `#[in_hacspec]`, +`#[unsafe_hacspec]`, etc. attributes that would tag the external definitions, +since these attributes get erased by the Rust compiler before reaching the +compiled crates metadata. + + +### Typechecking + +The typechecking is done in `typechecker.rs` and follows a very regular structure, +making heavy use of immutable data structures to not mess up the various +context manipulations. + +Note that we need to perform a full typechecking complete with method resolution +because the proof backends need very fine-grained typechecking information +to generate correct code. + +Be careful: types often need to be de-aliased with `dealias_type` before +being matched on structurally. Forgetting to dealias will lead to bugs with +type aliases. + +### Proof backends + +The different proof backends (`rustspec_to_fstar.rs`, etc) all enjoy a similar +structure that ought to be refactored to showcase their commonality. The backends +don't use an intermediate AST to generate the code in the proof assistant but +rather directly print code as string using the [`pretty`](https://crates.io/crates/pretty) +pretty-printing library. If you want to start a new proof backend, the easiest +solution is probably to copy an existing proof backend and tweak it until +you get the right result. + +The code generation has to be fine-tuned to interface with a replica of the +hacspec standard library in the host proof assistant, whose correspondence with +the original hacspec library in Rust is part of the trusted code base. More specially, +clever solutions to encode sequences and array, as well as all the different types +of public and secret machine integers, and the interaction between the two +(seeing a double as a string of bytes) have to be implemented through proof +assistant libraries. + +## Unit tests + +The compiler has various unit tests that are controlled trough the `language/tests` +files. Please enrich the unit tests bases in `language-tests`, +`negative-language-tests` and `test-crate` as you implement new features for +the compiler. The compiler can also be tested against all the hacspec cryptographic +specifications by running `examples/typecheck_examples.sh` from the root of +the repository. diff --git a/book/archive/src/developers/hacspec_architecture.png b/book/archive/src/developers/hacspec_architecture.png new file mode 100644 index 000000000..009b7cd5a Binary files /dev/null and b/book/archive/src/developers/hacspec_architecture.png differ diff --git a/book/archive/src/developers/readme.md b/book/archive/src/developers/readme.md new file mode 100644 index 000000000..23e631007 --- /dev/null +++ b/book/archive/src/developers/readme.md @@ -0,0 +1,4 @@ +# For Developers + +This section contains a handy guide for hacspec developers working on the +standard library or the compiler. diff --git a/book/archive/src/examples/readme.md b/book/archive/src/examples/readme.md new file mode 100644 index 000000000..46897eadd --- /dev/null +++ b/book/archive/src/examples/readme.md @@ -0,0 +1,13 @@ +# Examples + +The main [hacspec repository] contains a set of [example specifications]. +In this section we pull out some interesting bits to demonstrate the hacspec +language. + +There's also a provider that bundles the different cryptographic primitives +into a single library. +The provider implements the [RustCrypto traits] in order to facilitate interoperability. + +[RustCrypto traits]: https://github.com/RustCrypto/traits +[hacspec repository]: https://github.com/hacspec/hacspec/ +[example specifications]: https://github.com/hacspec/hacspec/tree/master/examples diff --git a/book/archive/src/language/core.md b/book/archive/src/language/core.md new file mode 100644 index 000000000..79ec4b596 --- /dev/null +++ b/book/archive/src/language/core.md @@ -0,0 +1,157 @@ +# The core of hacspec + +## Crates and modules + +hacspec only supports single-module crates, due to a technical limitation +of the Rust compiler. Inside this single file, a hacspec program shall always +start with: + +```rust, noplaypen +use hacspec_lib::*; + +// Optional: dependencies on other crates containing hacspec programs +use other_hacpsec_crate::*; +``` + +No other form of `use` is allowed in hacspec, because allowing Rust's +complex import patterns would increase the complexity of the hacspec compiler +and conflict with the module systems of most proof assistants. + +## Functions + +hacspec is a functional language, and only supports the declaration of +top-level functions: + +```rust, noplaypen +fn hacspec_function(x: bool) -> () { + ... +} +``` + +The functions can take any number of arguments, and may return a value (or not). +Note that recursive functions are forbidden in hacspec. + +The control flow inside hacspec functions is limited, as `return` statements +are forbidden. + +## Basic Types + +hacspec supports all the Rust primitive types: integers (signed and unsigned), +booleans, unit, tuples. hacspec possesses some support for generic +types, but only for primitive types defined by the language creators, and +not for user-defined types. + +Type aliases are allowed in hacspec: + +```rust, noplaypen +type OneTypeAlias = u32; +``` + +## Borrows + +hacspec forbids mutable borrows in all places. Immutable borrows are allowed +in hacspec, but only for function arguments. Indeed, you can declare a function +argument as immutably borrowed: + +```rust, noplaypen +fn hacspec_function(arg: &Seq) { + ... +} +``` + +You can also immutably borrow a value at the call site of a function: + +```rust, noplaypen +hacspec_function(&Seq::::new(64)) +``` + +In particular, return types cannot contain references, and the same is true +for types inside tuples or any data structure. + +## Constants + +hacspec allows the declaration of constants: + +```rust, noplaypen +const ONE_CONST : bool = false; +``` + +## Assignments + +Inside a function body, hacspec allows regular Rust let-bindings: + +```rust, noplaypen +let x = ...; +``` + +hacspec also allows mutable let bindings, and subsequent reassignments: + +```rust, noplaypen +let mut x = ...; +... +x = ...; +``` + +This allowing of mutable variable might come as a contradiction to hacspec's +philosophy of forbidding mutable state. But in fact, mutable local variables in +hacspec can be translated to a completely side-effect free form with a state-passing +like monadic structure. + +Left-hand sides of assignments support destructuring, which is currently the +only way to access the members of a tuple: + +```rust, noplaypen +let (x, y) = z; +``` + +## Loops + +Looping is severely restricted in hacspec compared to Rust, as the only accepted form is +`for` looping with a counter over an integer range: + +```rust, noplaypen +for i in low..hi { + ... // The block can use i and reassign mutable variables +} +``` + +The motivation for this restriction is to ease the proof of termination of +loops. `break` or `continue` statements are forbidden. + +## Conditionals + +hacspec allows statement-like conditionals as well as expression-like +conditionals: + +```rust, noplaypen +if cond1 { + ... // the block can modify mutable variables +} else { // else block is optional here + ... +} +let x = if cond2 { ... } else { ... }; +``` + +## Statements and expressions + +In regular Rust, statements and expressions can be mixed together freely. +This not the case in hacspec that imposes a strict precedence of statements +over expressions. For instance, the following code is not allowed in +hacspec: + +```rust, noplaypen +let x = if cond { + y = true; // ERROR: the reassignment is a statement, which cannot + // be contained in the expression to which x is assigned. + 3 +} else { + 4 +}; +``` + +## Visibility + +hacspec allows for both `pub` and non-`pub` versions of item declarations +(pub, non-pub, etc). You simply have to respect the Rust visibility rules. Note +that these visibility distinctions might not be translated in the proof +backends. diff --git a/book/archive/src/language/enums.md b/book/archive/src/language/enums.md new file mode 100644 index 000000000..7fc0975c8 --- /dev/null +++ b/book/archive/src/language/enums.md @@ -0,0 +1,71 @@ +# Structs and enums + +hacspec also supports user-defined structs and enums with some restrictions. + +## Structs + +The only form of struct declaration currently allowed in hacspec is: + +```rust, noplaypen +struct Foo(u32, Seq); +``` + +The struct thus declared can have one or more components. This form of struct +declaration effectively corresponds to a single-case enum, and is implemented +as such. Struct components can be accessed through let-binding destructuring: + +```rust, noplaypen +let Foo(x, y) = z; +``` + +Note that you can't store borrowed types inside hacspec structs, hence there is no +need for lifetime variables. + +## Enums + +hacspec supports very restricted `enum` declarations: + +```rust, noplaypen +enum Foo { + CaseA, + CaseB(u16), + CaseC(Seq, u64) +} +``` + +These declaration don't support the basic Rust features such as C-style +union declarations with assignments for each case. + +Enumeration values can be pattern-matched in an expression: + +```rust, noplaypen +match x { + Foo::CaseA => ..., + Foo::CaseB(y) => ..., + Foo::CaseC(y,z) => ... +} +``` + +Note that you can't store borrowed types inside hacspec enums, hence there is no +need for lifetime variables. + +## Option and Result + +User-defined structs and enums presented above don't support generic type +parameters yet. However, the built-in enums `Option` and `Result` +support type parameters. Those type parameters have to be explicitly declared +each time, as hacspec does not currently support type inference: + +```rust, noplaypen +match x { + Result::, bool>::Ok(y) => ..., + Result::, bool>::Err(err) => ... +} +``` + +Such type parameter declaration is cumbersome; as a workaround we advise +to declare a type alias as such: + +```rust, noplaypen +type MyResult = Result::, bool>; +``` diff --git a/book/archive/src/language/errors.md b/book/archive/src/language/errors.md new file mode 100644 index 000000000..30c3e6b0b --- /dev/null +++ b/book/archive/src/language/errors.md @@ -0,0 +1,16 @@ +# Error handling + +Error handling in Rust is done via the `Result` type (see the structs and +enums section). But on top of explicit pattern-matching, hacspec also +supports the popular `?` operator to quickly perform an early return and +propagate the error case upwards. + +`?` is only allowed at the very end of an expression in a let-binding or +reassignment statement: + +```rust, noplaypen +let x = foo(true)?; // GOOD +let y = foo(bar(0)?); // ERROR: the ? is not at the end of the statement +``` + +Currently, `?` is the only way to return early in a hacspec function. diff --git a/book/archive/src/language/readme.md b/book/archive/src/language/readme.md new file mode 100644 index 000000000..7d8d768c6 --- /dev/null +++ b/book/archive/src/language/readme.md @@ -0,0 +1,18 @@ +# The hacspec language + +This section gives an informal description of the hacspec language, whose +goal is to provide hands-on documentation for users of the language. For +a formal specification of the semantics of the language, please refer +to the [technical report][1]. + +hacspec is a domain-specific language embedded inside Rust. This means that +all correct hacspec programs are correct Rust programs: you can use +the usual Rust tooling for working on your hacspec developments. However, +hacspec is a strict subset of Rust: this means that some features of Rust +are forbidden inside hacspec. The goal of restricting the expressiveness of +the language is twofold: first, help domain experts such as cryptographers +convey their specifications in a fashion that should help them avoid +mistakes; second, provide a way for Rust programmers to interact with theorem +provers such as F\* or Coq. + +[1]: https://hal.inria.fr/hal-03176482 diff --git a/book/archive/src/language/seq.md b/book/archive/src/language/seq.md new file mode 100644 index 000000000..1f32d5d79 --- /dev/null +++ b/book/archive/src/language/seq.md @@ -0,0 +1,32 @@ +# Sequences and arrays + +## Sequences + +The staple `Vec` type is forbidden in hacspec. Instead, you have to use the +type `Seq`, which is implemented as a wrapper around `Vec`. + +The most notable differences between `Seq` and `Vec` is that `Seq` is not +resizable, and does not support `push` and `pop` operations. Instead, the +final length of the seq has to be provided at creation time. See the +hacspec standard library documentation for more details. + +`Seq` is a built-in generic type that always has to be indexed by the content of the +cells: `Seq`, etc. + +## Arrays + +The native Rust array types `[, ]` is forbidden in +hacspec. Instead, you have to declare nominally at the top-level new array types +for a specific cell content and size with: + +```rust, noplaypen +array!(FooArray, u8, 64); +// This declares type FooArray as an array of u8 of size 64 +bytes!(BarArray, 64); +// bytes! is a specialized version of array! with secret bytes +array!(BazArray, u8, 64, type_for_indexes:BazIndex); +// The additional argument type_for_indexes defines an alias of usize +// intended to spot which usizes are used to index BazArray (useful for +// verification) +``` + diff --git a/book/archive/src/language/syntax.md b/book/archive/src/language/syntax.md new file mode 100644 index 000000000..317173b0f --- /dev/null +++ b/book/archive/src/language/syntax.md @@ -0,0 +1,58 @@ +# Syntax + +``` +P ::= [i]\* Program items +i ::= array!(t, μ, n) Array type declaration where n is a natural number + | nat_mod!(t, n) Modular integer + | fn f([d]+) -> μ b Function declaration + | type t = enum { [c(μ)]+ } Enum declaration (with constructors) + | type t = struct([μ]+) Struct declaration (without named fields) + | const x: μ = e Constant declaration + | use crate::* External crate import + | use mod::* Internal module import +d ::= x: τ Function argument + | mut x: τ Mutable function argument +μ ::= unit|bool|u8|U8|i8|I8... Base types + | Seq<μ> Sequence + | String Strings + | ([μ]+) Tuple + | unit Unit type + | t Named type +τ ::= μ Plain type + | &μ Immutable reference +b ::= {[s;]+} Block +p ::= x Variable pattern + | ([p]+) Tuple pattern + | t (p) Struct constructor pattern + | _ Wildcard pattern +s ::= let p: τ = e Let binding + | let mut p: τ = e Mutable let binding + | x = e Variable reassignment + | x = e? Variable reassignment with result/option catching + | let p: τ = e? Let binding with result/option catching + | if e then b (else b) Conditional statements + | c(e) Enum injection + | match e { [c(p) => e]+ } Pattern matching + | for x in e..e b For loop (integers only) + | e Return expression + | b Statement block +e ::= ()|true|false Unit and boolean literals + | n Integer literal + | U8(e)|I8(e)|... Secret integer classification + | "..." String literal + | t([e]+) Array literal + | e as μ Integer casting + | x Variable + | () Unit + | f([a]+) Function call + | if e then e else e Conditional expression + | e ⊙ e Binary operations + | ⊘ e Unary operations + | ([e]+) Tuple constructor + | x[e] Array or sequence index +a ::= e Linear argument + | &e Call-site borrowing +⊙ ::= + | - | * | / | && + | || | == | != | > | < +⊘ ::= - | ~ +``` diff --git a/book/archive/src/misc/contributors.md b/book/archive/src/misc/contributors.md new file mode 100644 index 000000000..adc2dc245 --- /dev/null +++ b/book/archive/src/misc/contributors.md @@ -0,0 +1,15 @@ +# Contributors + +A list of contributors to the hacspec project. + +- Franziskus Kiefer ([franziskuskiefer](https://github.com/franziskuskiefer/)) +- Denis Merigoux ([denismerigoux](https://github.com/denismerigoux)) +- Karthik Bhargavan +- Tomer Yavor ([TomerHawk](https://github.com/TomerHawk)) +- Tanmay Garg ([tanmay2004](https://github.com/tanmay2004)) +- Peter Schwabe ([cryptojedi](https://github.com/cryptojedi)) +- Kaspar Schleiser ([kaspar030](https://github.com/kaspar030)) +- [Kasserne](https://github.com/Kasserne) +- Tony Arcieri ([tarcieri](https://github.com/tarcieri)) + +If you feel you're missing from this list, feel free to add yourself in a PR. \ No newline at end of file diff --git a/book/archive/src/readme.md b/book/archive/src/readme.md new file mode 100644 index 000000000..7f9bfcdb1 --- /dev/null +++ b/book/archive/src/readme.md @@ -0,0 +1,25 @@ +# Introduction + +hacspec is a specification language for crypto primitives, protocols, and more. +It is a subset of the [Rust] programming language, focused on functional +programming and it avoids the use of mutable state as much as possible. + +This book gives an overview of: +* [The hacspec language](./language); +* The different parts of the project: + * [the standard library](./std), + * [examples of hacspec programs](./examples); +* How to use hacspec to write [specifications] for standards and [verification]; +* How to use hacspec to generate [test vectors]; +* [Work on the hacspec compiler and tooling itself](./developers). + +For a quick introduction you can also check out these [slides] from April 2021. +An in-depth [technical report] is also available, and serves as a reference +for the language formalization. + +[slides]: https://raw.githubusercontent.com/hacspec/hacspec/master/presentation_slides.pdf +[technical report]: https://hal.inria.fr/hal-03176482 +[Rust]: https://www.rust-lang.org/ +[specifications]: ./usage/specifications.md +[verification]: ./usage/verification.md +[test vectors]: ./usage/test_vectors.md diff --git a/book/archive/src/std/abstract_integers.md b/book/archive/src/std/abstract_integers.md new file mode 100644 index 000000000..baf0324c5 --- /dev/null +++ b/book/archive/src/std/abstract_integers.md @@ -0,0 +1 @@ +# Astract integers diff --git a/book/archive/src/std/arithmetic.md b/book/archive/src/std/arithmetic.md new file mode 100644 index 000000000..43b116ae0 --- /dev/null +++ b/book/archive/src/std/arithmetic.md @@ -0,0 +1,76 @@ +# Arithmetic + +hacspec overloads the arithmetic operators for a wide variety of types +corresponding to mathematical values mentioned in cryptographic specifications. + +## The `Numeric` trait + +All of these types implement the `Numeric` trait defined by the hacspec standard +library. The arithmetic operators work for all kinds of integers, but also +arrays and sequences (point-wise operations). + +Note that the list of types implementing `Numeric` is hardcoded in the +hacspec compiler, and as of this day cannot be extended by the user. + +While the Rust compiler can infer the type of integer literals automatically, +this feature is not implemented by the hacspec compiler: + +``` +let w: u32 = 0; // ERROR: an integer without a suffix will have type usize +let x: u64 = 0x64265u64; // GOOD +let y: u64 = 4u64; // GOOD +``` + +## Public and secret integers + +One of hacspec's goal is to enable users to quickly check whether their +application does not obviously break the constant-time guarantee. +Certain processor instructions take more or less time to complete depending +on their inputs, which can cause secret leakage and break the security of +an application. Hence, hacspec offers for each type of integer (`u8`, `u32`, etc.) +a mirror secret integer type (`U8`, `U32`, etc.) for which operations +that break constant-timedness are forbidden. + +This public/private distinction can be found at a lot of places in the standard +library, and is made to forbid functions and data structures from leaking secrets. + +Conversions between public and secret integers are restricted to two functions: +`classify` and `declassify`. + +## Abstract integers + +Some cryptographic specifications talk about modular arithmetic in large +fields, whose size overflows even `u128`. To ease the expression of such +specifications, hacspec offers wrapper types around `BigInt` that can be +declared using the following API: + +```rust, noplaypen +abstract_nat_mod!( + NameOfModularInts, + NameOfUnderlyingByteRepresentation, + 256, // Number of bits for the representation of the big integer, + "ffffffffffffffff00000000000065442", // Hex representation of the modulo value as hex +) + +abstract_public_nat_mod!( + ... // Public version of above +) +``` + +## Integers as bytes + +It is often useful to view an integer as a sequence of bytes that can be +manipulated individually. The hacspec standard library provides a number +of function to translate back and forth from integer to sequence of bytes: + +```rust, noplaypen +pub fn u16_to_le_bytes(x: u16) -> u16Word; + +pub fn u16_from_le_bytes(s: u16Word) -> u16; + +pub fn U64_to_be_bytes(x: U64) -> U64Word; + +pub fn U64_from_be_bytes(s: U64Word) -> U64; + +... +``` diff --git a/book/archive/src/std/readme.md b/book/archive/src/std/readme.md new file mode 100644 index 000000000..039253473 --- /dev/null +++ b/book/archive/src/std/readme.md @@ -0,0 +1,15 @@ +# The hacspec std library + +The hacspec standard library contains a host of functions, type generators +and methods that define the base objects manipulated in classic cryptographic +primitives. + +Methods in the standard library can be divided into three categories: +1. The `not_hacspec` methods whose signature and body does not belong to the +hacspec fragment of Rust. They should not be used in hacspec code, but can +be used as helpers for e.g. testing. +2. The `unsafe_hacspec` methods whose signature belongs to hacspec but not +the body. These methods can be used in hacspec programs but their body +is part of the trusted codebase. +3. The `in_hacspec` methods whose signatures and bodies belong to the +hacspec fragment of Rust. These can be used safely in hacspec programs. diff --git a/book/archive/src/std/seq.md b/book/archive/src/std/seq.md new file mode 100644 index 000000000..319f3d5e2 --- /dev/null +++ b/book/archive/src/std/seq.md @@ -0,0 +1,58 @@ +# Sequence and array operations + +## Operations common to sequences and arrays + +### Base traits + +Some operations are common to both [sequences and arrays](/book/language/seq.md) +by design, and can be used as the interoperability base between the two types +of collections. These operations are the following: +* `len`: gives the length of an array or sequence; +* `iter`: iterates over the content of the array or sequence +(unsafe in hacspec but can be used for implementing primitives) +* `create`: creates a sequence or array and initializes the elements to the +default value (0 for arithmetic types); +* `update_slice`, `update` and `update_start`: produce a new sequence or array +with modified contents. + +Both sequences and arrays implement indexing with any type of unsigned public +integer. + +### Chunking + +Both arrays and sequences support chunking with methods like: +* `num_chunks` and `num_exact_chunks` (whole or partial blocks); +* `get_chunk`, `get_exact_chunk` and `get_remainder_chunk`; +* `set_chunk` and `set_exact_chunk`. + +The read operations borrow the sequence or array, but the write operations +create a new sequence or array. + +### Conversions + +Sequences and arrays can be created from other types via methods like: +* `from_public_slice` and `from_slice`; +* `from_vec` and `from_native_slice`; +* `from_public_seq` and `from_seq` (to convert a seq into an array of the correct size); +* `from_string` and `from_hex` for byte or hex strings (hex only for `u8` sequences and arrays). + +### Secrecy + +The methods prefixed by `public` performs an element-wise classification of the +data under the hood. + +### Ownage + +Some methods have two versions: an `owned` and a non-`owned` version, depending +on whether the `self` argument is consumed or not by the method. This distinction +is useful to avoid unnecessary copies and thus be more performant. + +## Array-specific operations + +Since array length is known statically, `new` does not take any argument, +same as `length`. `slice`s of arrays become `Seq`. + +## Sequence-specific operations + +Sequences can be extended (by creating a new sequence under the hood) with +`push` or `concat`. Sequences can also be sliced with `slice`. diff --git a/book/archive/src/usage/readme.md b/book/archive/src/usage/readme.md new file mode 100644 index 000000000..8f04b05ad --- /dev/null +++ b/book/archive/src/usage/readme.md @@ -0,0 +1 @@ +# Usage diff --git a/book/archive/src/usage/specifications.md b/book/archive/src/usage/specifications.md new file mode 100644 index 000000000..247b1857d --- /dev/null +++ b/book/archive/src/usage/specifications.md @@ -0,0 +1 @@ +# Specifications diff --git a/book/archive/src/usage/test_vectors.md b/book/archive/src/usage/test_vectors.md new file mode 100644 index 000000000..4e7735f6c --- /dev/null +++ b/book/archive/src/usage/test_vectors.md @@ -0,0 +1 @@ +# Test Vectors diff --git a/book/archive/src/usage/verification.md b/book/archive/src/usage/verification.md new file mode 100644 index 000000000..d7ae51f2d --- /dev/null +++ b/book/archive/src/usage/verification.md @@ -0,0 +1,65 @@ +# Verification + +## Coq + +### QuickCheck / QuickChick + +You can test your hacspec code using [QuickCheck](https://github.com/BurntSushi/quickcheck) (a Rust library for randomized property-based testing), by simply implementing `quickcheck::Arbitrary` for the type you want to generate tests for. For example: +```rust,ignore +impl Arbitrary for Fp { + fn arbitrary(g: &mut Gen) -> Fp { + let mut a: [u64; 6] = [0; 6]; + for i in 0..6 { + a[i] = u64::arbitrary(g); + } + let mut b: [u8; 48] = [0; 48]; + for i in 0..6 { + let val: u64 = a[i]; + b[(i*8)..((i+1)*8)].copy_from_slice(&(val.to_le_bytes())); + } + Fp::from_byte_seq_le(Seq::::from_public_slice(&b)) + } +} +``` +then you can use the `quickcheck` attribute, to make QuickCheck do property based testing for this function: +```rust,ignore +#[cfg(test)] +#[quickcheck] //Using the fp arbitraty implementation from above to generate fp2 elements. +fn test_fp2_prop_add_neg(a: Fp2) -> bool { + let b = fp2neg(a); + fp2fromfp(Fp::ZERO()) == fp2add(a, b) +} +``` +which will run when you do `cargo test`. If you then add the tag `#[cfg(proof)]` and export to Coq, +``` +cargo hacspec -o coq/src/.v +``` +then you get corresponding [QuickChick](https://github.com/QuickChick/QuickChick) test, +``` +Definition test_fp2_prop_add_neg (a_320 : fp2) : bool := + let b_321 := + fp2neg (a_320) in + (fp2fromfp (nat_mod_zero )) =.? (fp2add (a_320) (b_321)). + +QuickChick (forAll g_fp2 (fun a_320 : fp2 =>test_fp2_prop_add_neg a_320)). +``` +and generators will be constructed for the types automatically as, +``` +Instance show_fp : Show (fp) := Build_Show (fp) (fun x => show (GZnZ.val _ x)). +Definition g_fp : G (fp) := @bindGen Z (fp) (arbitrary) (fun x => returnGen (@Z_in_nat_mod _ x)). +Instance gen_fp : Gen (fp) := Build_Gen fp g_fp. +``` +which you can then run through coq in the folder `coq/` +``` +coqc -R src/ Hacspec src/.v +``` +Make sure you run: +``` +coqc -R src/ Hacspec src/MachineIntegers.v +coqc -R src/ Hacspec src/Lib.v +``` +or `make` to generate the `.vo` files used by `.v`. + +For more information: +- on QuickCheck (in rust): [BurntSushi/quickcheck](https://github.com/BurntSushi/quickcheck) +- on QuickChick: [Software foundations book on QuickChick](https://softwarefoundations.cis.upenn.edu/qc-current/index.html) diff --git a/book/book.toml b/book/book.toml new file mode 100644 index 000000000..c7377ded6 --- /dev/null +++ b/book/book.toml @@ -0,0 +1,10 @@ +[book] +authors = ["Franziskus Kiefer"] +language = "en" +multilingual = false +src = "src" +title = "hax" + +[output.html] +mathjax-support = true + diff --git a/book/default.nix b/book/default.nix new file mode 100644 index 000000000..98580862c --- /dev/null +++ b/book/default.nix @@ -0,0 +1,15 @@ +{ + stdenv, + mdbook, +}: +stdenv.mkDerivation { + name = "hax-book"; + src = ./.; + buildInputs = [mdbook]; + buildPhase = '' + mdbook build + mdbook build archive -d ../book/archive + bash ./postprocess.sh + ''; + installPhase = "mv book $out"; +} diff --git a/book/postprocess.sh b/book/postprocess.sh new file mode 100755 index 000000000..79d4a55ae --- /dev/null +++ b/book/postprocess.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env sh + +# This file replaces `user-checkable` with actual +# checkboxes and adds CSS to the generated HTML. + +for file in $(find . -name '*.html'); do + sed -i 's|user-checkable||g' "$file" +done + +for css in $(find . -name 'general.css'); do + cat >> "$css" <<-EOF +input.user-checkable { + transform: scale(1.5); + margin-right: 8px; + margin-left: 8px; +} + +ul:has(> li > .user-checkable) { + list-style-type: none; + padding: 0; + margin: 0; +} +li:has(> .user-checkable) { + list-style-type: none; + padding: 0; + margin: 0; +} +EOF +done diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md new file mode 100644 index 000000000..7da2c743f --- /dev/null +++ b/book/src/SUMMARY.md @@ -0,0 +1,30 @@ +# Summary + +- [Introduction](./readme.md) +- [Examples]() +- [Quick start](quick_start/intro.md) +- [Tutorial](tutorial/readme.md) + - [Panic freedom](tutorial/panic-freedom.md) + - [Properties on functions](tutorial/properties.md) + - [Data invariants](tutorial/data-invariants.md) +- [Proofs]() + - [F*]() + - [Coq]() + - [`libcore`]() +- [Troubleshooting/FAQ](faq/into.md) + - [Command line usage]() + - [The include flag: which items should be extracted, and how?](faq/include-flags.md) +- [Contributing]() + - [Structure]() + - [Hax Cargo subcommand]() + - [Frontend: the Rustc driver]() + - [Frontend: the exporter]() + - [Engine]() + - [Backends]() + - [Utilities]() + - [Libraries & Macros](contributing/libraries_macros.md) + - [`libcore`]() + +--- +[Contributors]() +[Archive](misc/archive.md) diff --git a/book/src/contributing/backends.md b/book/src/contributing/backends.md new file mode 100644 index 000000000..e69de29bb diff --git a/book/src/contributing/engine.md b/book/src/contributing/engine.md new file mode 100644 index 000000000..e69de29bb diff --git a/book/src/contributing/exporter.md b/book/src/contributing/exporter.md new file mode 100644 index 000000000..e69de29bb diff --git a/book/src/contributing/hax-cargo-subcommand.md b/book/src/contributing/hax-cargo-subcommand.md new file mode 100644 index 000000000..e69de29bb diff --git a/book/src/contributing/libcore.md b/book/src/contributing/libcore.md new file mode 100644 index 000000000..e69de29bb diff --git a/book/src/contributing/libraries_macros.md b/book/src/contributing/libraries_macros.md new file mode 100644 index 000000000..dfd145c61 --- /dev/null +++ b/book/src/contributing/libraries_macros.md @@ -0,0 +1,25 @@ +# Libraries + +# Macros and attributes +The hax engine understands only one attribute: `#[_hax::json(PAYLOAD)]`, +where `PAYLOAD` is a JSON serialization of the Rust enum +`hax_lib_macros_types::AttrPayload`. + +Note `#[_hax::json(PAYLOAD)]` is a [tool +attribute](https://github.com/rust-lang/rust/issues/66079): an +attribute that is never expanded. + +In the engine, the OCaml module `Attr_payloads` offers an API to query +attributes easily. The types in crate `hax_lib_macros_types` and +corresponding serializers/deserializers are automatically generated in +OCaml, thus there is no manual parsing involved. + +## User experience +Asking the user to type `#[_hax::json(some_long_json)]` is not very +friendly. Thus, the crate `hax-lib-macros` defines a bunch of [proc +macros](https://doc.rust-lang.org/beta/reference/procedural-macros.html) +that defines nice and simple-to-use macros. Those macro take care of +cooking some `hax_lib_macros_types::AttrPayload` payload(s), then +serialize those payloads to JSON and produce one or more +`#[_hax::json(serialized_payload)]` attributes. + diff --git a/book/src/contributing/readme.md b/book/src/contributing/readme.md new file mode 100644 index 000000000..e69de29bb diff --git a/book/src/contributing/rustc-driver.md b/book/src/contributing/rustc-driver.md new file mode 100644 index 000000000..e69de29bb diff --git a/book/src/contributing/structure.md b/book/src/contributing/structure.md new file mode 100644 index 000000000..e69de29bb diff --git a/book/src/contributing/utilities.md b/book/src/contributing/utilities.md new file mode 100644 index 000000000..e69de29bb diff --git a/book/src/examples/readme.md b/book/src/examples/readme.md new file mode 100644 index 000000000..e69de29bb diff --git a/book/src/faq/include-flags.md b/book/src/faq/include-flags.md new file mode 100644 index 000000000..ff6fbe1d6 --- /dev/null +++ b/book/src/faq/include-flags.md @@ -0,0 +1,65 @@ +# The include flag: which items should be extracted, and how? + +Often, you need to extract only a portion of a crate. The subcommand +`cargo hax into` accepts the `-i` flag which will help you to include +or exclude items from the extraction. + +Consider the following `lib.rs` module of a crate named `mycrate`. + +```rust +fn interesting_function() { aux() } +fn aux() { foo::f() } +fn something_else() { ... } +mod foo { + fn f() { ... } + fn g() { ... } + fn h() { ... } + fn interesting_function() { something() } + fn something() { ... } + mod bar { + fn interesting_function() { ... } + } +} +fn not_that_one() { not_that_one_dependency() } +fn not_that_one_dependency() { ... } +``` + +Here are a few examples of the `-i` flag. + - `cargo hax into -i '-** +mycrate::**::interesting_function' ` + The first clause `-**` makes items not to be extracted by default. + This extracts any item that matches the [glob pattern](https://en.wikipedia.org/wiki/Glob_(programming)) `mycrate::**::interesting_function`, but also any (local) dependencies of such items. `**` matches any sub-path. + Thus, the following items will be extracted: + + `mycrate::interesting_function` (direct match); + + `mycrate::foo::interesting_function` (direct match); + + `mycrate::foo::bar::interesting_function` (direct match); + + `mycrate::aux` (dependency of `mycrate::interesting_function`); + + `mycrate::foo::f` (dependency of `mycrate::aux`); + + `mycrate::foo::something` (dependency of `mycrate::foo::interesting_function`). + - `cargo hax into -i '+** -*::not_that_one' ` + Extracts any item but the ones named `::not_that_one`. Here, + everything is extracted but `mycrate::not_that_one`, including + `mycrate::not_that_one_dependency`. + - `cargo hax into -i '-** +!mycrate::interesting_function' ` + Extracts only `mycrate::interesting_function`, not taking into + account dependencies. + - `cargo hax into -i '-** +~mycrate::interesting_function' ` + Extracts `mycrate::interesting_function` and its direct + dependencies (no transitivity): this includes `mycrate::aux`, but + not `mycrate::foo::f`. + +Now, suppose we add the function `not_extracting_function` +below. `not_extracting_function` uses some unsafe code: this is not +supported by hax. However, let's suppose we have a functional model +for this function and that we still want to extract it as an +axiomatized, assumed symbol. +```rust +fn not_extracting_function(u8) -> u8 { + ... + unsafe { ... } + ... +} +``` + + - `cargo hax into -i '+:mycrate::not_extracting_function' ` + Extracts `mycrate::not_extracting_function` in signature-only mode. + diff --git a/book/src/faq/into.md b/book/src/faq/into.md new file mode 100644 index 000000000..cefa77ebd --- /dev/null +++ b/book/src/faq/into.md @@ -0,0 +1,3 @@ +# Troubleshooting/FAQ + +This chapter captures a list of common questions or issues and how to resolve them. If you happen to run into an issue that is not documented here, please consider submitting a pull request! diff --git a/book/src/misc/archive.md b/book/src/misc/archive.md new file mode 100644 index 000000000..923376fd0 --- /dev/null +++ b/book/src/misc/archive.md @@ -0,0 +1,7 @@ + +# Warning: this book is currently being rewritten! + +hax is the successor of hacspec. You can find the previous book +describing hacspec [here](../archive/index.html), but keep in mind most of the information +there is outdated. + diff --git a/book/src/misc/contributors.md b/book/src/misc/contributors.md new file mode 100644 index 000000000..e69de29bb diff --git a/book/src/proofs/coq.md b/book/src/proofs/coq.md new file mode 100644 index 000000000..e69de29bb diff --git a/book/src/proofs/fstar.md b/book/src/proofs/fstar.md new file mode 100644 index 000000000..e69de29bb diff --git a/book/src/proofs/libcore.md b/book/src/proofs/libcore.md new file mode 100644 index 000000000..e69de29bb diff --git a/book/src/proofs/readme.md b/book/src/proofs/readme.md new file mode 100644 index 000000000..e69de29bb diff --git a/book/src/quick_start/intro.md b/book/src/quick_start/intro.md new file mode 100644 index 000000000..341bcf01f --- /dev/null +++ b/book/src/quick_start/intro.md @@ -0,0 +1,86 @@ +# Quick start with hax and F* + +Do you want to try hax out on a Rust crate of yours? This chapter is +what you are looking for! + +## Setup the tools + + - **user-checkable** [Install the hax toolchain](https://github.com/hacspec/hax?tab=readme-ov-file#installation). + 🪄 Running `cargo hax --version` should print some version info. + - **user-checkable** [Install F*](https://github.com/FStarLang/FStar/blob/master/INSTALL.md) *(optional: only if want to run F\*)* + +## Setup the crate you want to verify + +*Note: the instructions below assume you are in the folder of the specific crate (**not workspace!**) you want to extract.* + +*Note: this part is useful only if you want to run F\*.* + + + - **user-checkable** Create the folder `proofs/fstar/extraction` folder, right next to the `Cargo.toml` of the crate you want to verify. + 🪄 `mkdir -p proofs/fstar/extraction` + - **user-checkable** Copy [this makefile](https://gist.github.com/W95Psp/4c304132a1f85c5af4e4959dd6b356c3) to `proofs/fstar/extraction/Makefile`. + 🪄 `curl -o proofs/fstar/extraction/Makefile https://gist.githubusercontent.com/W95Psp/4c304132a1f85c5af4e4959dd6b356c3/raw/Makefile` + - **user-checkable** Add `hax-lib` as a dependency to your crate. + 🪄 `cargo add --git https://github.com/hacspec/hax hax-lib` + 🪄 *(`hax-lib` is not mandatory, but this guide assumes it is present)* + +## Partial extraction + +*Note: the instructions below assume you are in the folder of the +specific crate you want to extract.* + +Run the command `cargo hax into fstar` to extract every item of your +crate as F* modules in the subfolder `proofs/fstar/extraction`. + +**What is critical? What is worth verifying?** +Probably, your Rust crate contains mixed kinds of code: some parts are +critical (e.g. the library functions at the core of your crate) while +some others are not (e.g. the binary driver that wraps the +library). In this case, you likely want to extract only partially your +crate, so that you can focus on the important part. + +**Partial extraction.** +If you want to extract a function +`your_crate::some_module::my_function`, you need to tell `hax` to +extract nothing but `my_function`: + +```bash +cargo hax into -i '-** +your_crate::some_module::my_function' fstar +``` + +Note this command will extract `my_function` but also any item +(function, type, etc.) from your crate which is used directly or +indirectly by `my_function`. If you don't want the dependency, use +`+!` instead of `+` in the `-i` flag. + +**Unsupported Rust code.** +hax [doesn't support every Rust +constructs](https://github.com/hacspec/hax?tab=readme-ov-file#supported-subset-of-the-rust-language), +`unsafe` code, or complicated mutation scheme. That is another reason +for extracting only a part of your crate. When running hax, if an item +of your crate, say a function `my_crate::f`, is not handled by hax, +you can append `-my_crate::f` to the `-i` flag. You can learn more +about the `-i` flag [in the FAQ](../faq/include-flags.html). + + + +## Start F* verification +After running the hax toolchain on your Rust code, you will end up +with various F* modules in the `proofs/fstar/extraction` folder. The +`Makefile` in `proofs/fstar/extraction` will run F*. + +1. **Lax check:** the first step is to run `OTHERFLAGS="--lax" make`, + which will run F* in "lax" mode. The lax mode just makes sure basic + typechecking works: it is not proving anything. This first step is + important because there might be missing libraries. If F* is not + able to find a definition, it is probably a `libcore` issue: you + probably need to edit the F* library, which lives in the + `proofs-libs` directory in the root of the hax repo. +2. **Typecheck:** the second step is to run `make`. This will ask F* + to typecheck fully your crate. This is very likely that you need to + add preconditions and postconditions at this stage. Indeed, this + second step is about panic freedom: if F* can typecheck your crate, + it means your code *never* panics, which already is an important + property. + +To go further, please read the next chapter. diff --git a/book/src/readme.md b/book/src/readme.md new file mode 100644 index 000000000..c4880e4ce --- /dev/null +++ b/book/src/readme.md @@ -0,0 +1,14 @@ +# Introduction + +hax is a tool for high assurance translations that translates a large subset of +Rust into formal languages such as [F\*](https://www.fstar-lang.org/) or [Coq](https://coq.inria.fr/). +This extends the scope of the hacspec project, which was previously a DSL embedded in Rust, +to a usable tool for verifying Rust programs. + +> So what is **hacspec** now? + +hacspec is the functional subset of Rust that can be used, together with a hacspec +standard library, to write succinct, executable, and verifiable specifications in +Rust. +These specifications can be translated into formal languages with hax. + diff --git a/book/src/tutorial/Cargo.lock b/book/src/tutorial/Cargo.lock new file mode 100644 index 000000000..9675766ca --- /dev/null +++ b/book/src/tutorial/Cargo.lock @@ -0,0 +1,239 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "dyn-clone" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" + +[[package]] +name = "getrandom" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "hax-lib" +version = "0.1.0-pre.1" +source = "git+https://github.com/hacspec/hax#d668de4d17e5ddee3a613068dc30b71353a9db4f" + +[[package]] +name = "hax-lib-macros" +version = "0.1.0-pre.1" +source = "git+https://github.com/hacspec/hax#d668de4d17e5ddee3a613068dc30b71353a9db4f" +dependencies = [ + "hax-lib-macros-types", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "hax-lib-macros-types" +version = "0.1.0-pre.1" +source = "git+https://github.com/hacspec/hax#d668de4d17e5ddee3a613068dc30b71353a9db4f" +dependencies = [ + "proc-macro2", + "quote", + "schemars", + "serde", + "serde_json", + "uuid", +] + +[[package]] +name = "itoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" + +[[package]] +name = "libc" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ryu" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" + +[[package]] +name = "schemars" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45a28f4c49489add4ce10783f7911893516f15afe45d015608d41faca6bc4d29" +dependencies = [ + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c767fd6fa65d9ccf9cf026122c1b555f2ef9a4f0cea69da4d7dbc3e258d30967" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 1.0.109", +] + +[[package]] +name = "serde" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "serde_derive_internals" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "serde_json" +version = "1.0.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.52" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tutorial-src" +version = "0.1.0" +dependencies = [ + "hax-lib", + "hax-lib-macros", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "uuid" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a" +dependencies = [ + "getrandom", +] + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/book/src/tutorial/Cargo.toml b/book/src/tutorial/Cargo.toml new file mode 100644 index 000000000..de5569b89 --- /dev/null +++ b/book/src/tutorial/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "tutorial-src" +version = "0.1.0" +edition = "2021" + +[lib] +path = "sources.rs" + +[dependencies] +hax-lib = { git = "https://github.com/hacspec/hax", version = "0.1.0-pre.1" } diff --git a/book/src/tutorial/Sources.fst b/book/src/tutorial/Sources.fst new file mode 100644 index 000000000..cedf378a5 --- /dev/null +++ b/book/src/tutorial/Sources.fst @@ -0,0 +1,110 @@ +module Tutorial_src +#set-options "--fuel 0 --ifuel 1 --z3rlimit 150" +open Core +open FStar.Mul + +// ANCHOR: F3 +type t_F3 = + | F3_E1 : t_F3 + | F3_E2 : t_F3 + | F3_E3 : t_F3 + +let t_F3_cast_to_repr (x: t_F3) : isize = + match x with + | F3_E1 -> isz 0 + | F3_E2 -> isz 1 + | F3_E3 -> isz 3 +// ANCHOR_END: F3 + +// ANCHOR: barrett +unfold +let t_FieldElement = i32 + +let v_BARRETT_MULTIPLIER: i64 = 20159L + +let v_BARRETT_R: i64 = 67108864L + +let v_BARRETT_SHIFT: i64 = 26L + +let v_FIELD_MODULUS: i32 = 3329l + +let barrett_reduce (value: i32) + : Pure i32 + (requires + (Core.Convert.f_from value <: i64) >=. (Core.Ops.Arith.Neg.neg v_BARRETT_R <: i64) && + (Core.Convert.f_from value <: i64) <=. v_BARRETT_R) + (ensures + fun result -> + let result:i32 = result in + result >. (Core.Ops.Arith.Neg.neg v_FIELD_MODULUS <: i32) && result <. v_FIELD_MODULUS && + (result %! v_FIELD_MODULUS <: i32) =. (value %! v_FIELD_MODULUS <: i32)) = + let t:i64 = (Core.Convert.f_from value <: i64) *! v_BARRETT_MULTIPLIER in + let t:i64 = t +! (v_BARRETT_R >>! 1l <: i64) in + let quotient:i64 = t >>! v_BARRETT_SHIFT in + let quotient:i32 = cast (quotient <: i64) <: i32 in + let sub:i32 = quotient *! v_FIELD_MODULUS in + let _:Prims.unit = Tutorial_src.Math.Lemmas.cancel_mul_mod quotient 3329l in + value -! sub +// ANCHOR_END: barrett + +// ANCHOR: encrypt_decrypt +let decrypt (ciphertext key: u32) : u32 = ciphertext ^. key + +let encrypt (plaintext key: u32) : u32 = plaintext ^. key +// ANCHOR_END: encrypt_decrypt + + + + + + + +// ANCHOR: encrypt_decrypt_identity +let encrypt_decrypt_identity (key plaintext: u32) + : Lemma (requires true) + (ensures (decrypt (encrypt plaintext key <: u32) key <: u32) =. plaintext) = () +// ANCHOR_END: encrypt_decrypt_identity + +// ANCHOR: square +let square (x: u8) : u8 = x *! x +// ANCHOR_END: square + +// ANCHOR: square_ensures +let square_ensures (x: u8) + : Pure u8 + (requires x <. 16uy) + (ensures fun result -> result >=. x) + = x *! x +// ANCHOR_END: square_ensures + +// ANCHOR: square_option +let square_option (x: u8) : Core.Option.t_Option u8 = + if x >=. 16uy + then Core.Option.Option_None <: Core.Option.t_Option u8 + else Core.Option.Option_Some (x *! x) <: Core.Option.t_Option u8 +// ANCHOR_END: square_option + +// ANCHOR: square_requires +let square_requires (x: u8) + : Pure u8 (requires x <. 16uy) (requires fun _ -> True) + = x *! x +// ANCHOR_END: square_requires + +// ANCHOR: F +let v_Q: u16 = 2347us + +type t_F = { f_v:f_v: u16{f_v <. v_Q} } +// ANCHOR_END: F + +// ANCHOR: AddF +[@@ FStar.Tactics.Typeclasses.tcinstance] +let impl: Core.Ops.Arith.t_Add t_F t_F = + { + f_Output = t_F; + f_add_pre = (fun (self: t_F) (rhs: t_F) -> true); + f_add_post = (fun (self: t_F) (rhs: t_F) (out: t_F) -> true); + f_add = fun (self: t_F) (rhs: t_F) -> { + f_v = (self.f_v +! rhs.f_v <: u16) %! v_Q + } <: t_F + } +// ANCHOR_END: AddF diff --git a/book/src/tutorial/data-invariants.md b/book/src/tutorial/data-invariants.md new file mode 100644 index 000000000..a6777795f --- /dev/null +++ b/book/src/tutorial/data-invariants.md @@ -0,0 +1,78 @@ +# Data invariants + +In the two previous chapters we saw how to write specifications on +functions, be it with pre and post-condition or with lemmas. In this +chapter, we will see how to maintain invariants with precise types. + +## Making illegal states unpresentable +With the Barrett example, we were working on a certain field, whose +elements were represented as `i32` integers. To simplify, let's +consider `F₃`, the finite field with 3 elements (say `0`, `1` and +`2`). Every element of `F3` can be represented as a `i32` integers, +but the converse doesn't hold: the vast majority of `i32` integers are +not in of `F₃`. + +Representing `F₃` as `i32`s, every time we define a function consuming +`F₃` elements, we face the risk to consume *illegal* elements. We are +thus back to [chapter 4.1](panic-freedom.md): we should panic on +illegal elements, and add hax pre-conditions on every single +function. That's not ideal: the property of being either `0`, `1` or +`2` should be encoded directly on the type representing `F₃` elements. + +### `enum`s to then rescue +Rust alone already can solve our representation issues with +[enums](https://doc.rust-lang.org/book/ch06-00-enums.html)! Below, we +define the `enum` type `F3` which has only three constructor: `F3` +represent exactly the elements of `F₃`, not more, not less. + +```rust,noplaypen +{{#include sources.rs:F3}} +``` +```ocaml +{{#include Sources.fst:F3}} +``` + +With `F3`, there doesn't exist illegal values at all: we can now +define [*total* +functions](https://en.wikipedia.org/wiki/Partial_function) on `F₃` +elements. We dropped altogether a source of panic! + +Soon you want to work with a bigger finite field: say +`F₂₃₄₇`. Representing this many `q` different elements with an Rust +enum would be very painful... The `enum` apporach falls appart. + +### Newtype and refinements +Since we don't want an `enum` with 2347 elements, we have to revert to +a type that can hold this many elements. The smallest integer type +large enough provided by Rust is `u16`. + +Let's define `F` a +["newtype"](https://matklad.github.io/2018/06/04/newtype-index-pattern.html): +a [struct](https://doc.rust-lang.org/book/ch05-00-structs.html) with +one `u16` field `v`. Notice the refinment annotation on `v`: the +extraction of this type `F` via hax will result in a type enforcing +`v` small enough. + +```rust,noplaypen +{{#include sources.rs:F}} +``` +```ocaml +{{#include Sources.fst:F}} +``` + +In Rust, we can now define functions that operates on type `F`, +assuming they are in bounds with respect to `F₂₃₄₇`: every such +assumption will be checked and enforced by the proof assistant. As an +example, below is the implementation of the addition for type `F`. + +```rust,noplaypen +{{#include sources.rs:AddF}} +``` +```ocaml +{{#include Sources.fst:AddF}} +``` + +Here, F* is able to prove automatically that (1) the addition doesn't +overflow and (2) that the invariant of `F` is preserved. The +definition of type `F` in F* (named `t_F`) very explicitely requires +the invariant as a refinement on `v`. diff --git a/book/src/tutorial/panic-freedom.md b/book/src/tutorial/panic-freedom.md new file mode 100644 index 000000000..38d2f2c33 --- /dev/null +++ b/book/src/tutorial/panic-freedom.md @@ -0,0 +1,121 @@ +# Panic freedom + +Let's start with a simple example: a function that squares a `u8` +integer. To extract this function to F* using hax, we simply need to +run the command `cargo hax into fstar` in the directory of the crate +in which the function `square` is defined. + +*Note: throughout this tutorial, you can inspect the hax extraction to +F\* for each code Rust snippets, by clicking on the "F\* extraction" +tab.* + +```rust,noplaypen +{{#include sources.rs:square}} +``` +```ocaml +{{#include Sources.fst:square}} +``` + +Though, if we try to verify this function, F* is complaining about a +subtyping issue: F* tells us that it is not able to prove that the +result of the multiplication `x * x` fits the range of `u8`. The +multiplication `x * x` might indeed be overflowing! + +For instance, running `square(16)` panics: `16 * 16` is `256`, which +is just over `255`, the largest integer that fits `u8`. Rust does not +ensure that functions are *total*: a function might panic at any +point, or might never terminate. + +## Rust and panicking code +Quoting the chapter [To `panic!` or Not to +`panic!`](https://doc.rust-lang.org/book/ch09-03-to-panic-or-not-to-panic.html) +from the Rust book: + +> The `panic!` macro signals that your program is in a state it can't +> handle and lets you tell the process to stop instead of trying to +> proceed with invalid or incorrect values. + +A Rust program should panics only in a situation where an assumption +or an invariant is broken: a panics models an *invalid* state. Formal +verification is about proving such invalid state cannot occur, at all. + +From this observation emerges the urge of proving Rust programs to be +panic-free! + +## Fixing our squaring function +Let's come back to our example. There is an informal assumption to the +multiplication operator in Rust: the inputs should be small enough so +that the addition doesn't overflow. + +Note that Rust also provides `wrapping_mul`, a non-panicking variant +of the multiplication on `u8` that wraps when the result is bigger +than `255`. Replacing the common multiplication with `wrapping_mul` in +`square` would fix the panic, but then, `square(256)` returns zero. +Semantically, this is not what one would expect from `square`. + +Our problem is that our function `square` is well-defined only when +its input is within `0` and `15`. + +### Solution A: reflect the partialness of the function in Rust +A first solution is to make `square` return an `Option` instead of a `u8`: +```rust,noplaypen +{{#include sources.rs:square_option}} +``` +```ocaml +{{#include Sources.fst:square_option}} +``` + +Here, F* is able to prove panic-freedom: calling `square` with any +input is safe. Though, one may argue that `square`'s input being small +enough should really be an assumption. Having to deal with the +possible integer overflowing whenever squaring is a huge burden. Can +we do better? + +### Solution B: add a precondition +The type system of Rust doesn't allow the programmer to formalize the +assumption that `square` expects a small `u8`. This becomes +possible using hax: one can annotate a function with a pre-condition +on its inputs. + +The pre-conditions and post-conditions on a function form a +*contract*: "if you give me some inputs that satisfies a given formula +(*the precondition*), I will produce a return value that satisfy +another formula (*the postcondition*)". Outside this contracts, +anything might happen: the function might panic, might run forever, +erase your disk, or anything. + +The helper crate +[hax-lib-macros](https://github.com/hacspec/hax/tree/main/hax-lib-macros) +provdes the `requires` +[proc-macro](https://doc.rust-lang.org/reference/procedural-macros.html) +which lets user writting pre-conditions directly in Rust. + +```rust,noplaypen +{{#include sources.rs:square_requires}} +``` +```ocaml +{{#include Sources.fst:square_requires}} +``` + +With this precondition, F* is able to prove panic freedom. From now +on, it is the responsability of the clients of `square` to respect the +contact. The next step is thus be to verify, through hax extraction, +that `square` is used correctly at every call site. + +## Common panicking situations +Mutipication is not the only panicking function provided by the Rust +library: most of the other integer arithmetic operation have such +informal assumptions. + +Another source of panics is indexing. Indexing in an array, a slice or +a vector is a partial operation: the index might be out of range. + +In the example folder of hax, you can find the [`chacha20` +example](https://github.com/hacspec/hax/blob/main/examples/chacha20/src/lib.rs) +that makes use of pre-conditions to prove panic freedom. + +Another solution for safe indexing is to use the [newtype index +pattern](https://matklad.github.io/2018/06/04/newtype-index-pattern.html), +which is [also supported by +hax](https://github.com/hacspec/hax/blob/d668de4d17e5ddee3a613068dc30b71353a9db4f/tests/attributes/src/lib.rs#L98-L126). The [data invariants](data-invariants.md#newtype-and-refinements) chapter gives more details about this. + diff --git a/book/src/tutorial/proofs/fstar/extraction/Makefile b/book/src/tutorial/proofs/fstar/extraction/Makefile new file mode 100644 index 000000000..b346e98f5 --- /dev/null +++ b/book/src/tutorial/proofs/fstar/extraction/Makefile @@ -0,0 +1,139 @@ +# This is a generically useful Makefile for F* that is self-contained +# +# It is tempting to factor this out into multiple Makefiles but that +# makes it less portable, so resist temptation, or move to a more +# sophisticated build system. +# +# We expect: +# 1. `fstar.exe` to be in PATH (alternatively, you can also set +# $FSTAR_HOME to be set to your F* repo/install directory) +# +# 2. `cargo`, `hax` and `rustup` to be installed and in PATH. +# +# 3. the extracted Cargo crate to have "hax-lib" as a dependency: +# `hax-lib = { version = "0.1.0-pre.1", git = "https://github.com/hacspec/hax"}` +# +# Optionally, you can set `HACL_HOME`. +# +# ROOTS contains all the top-level F* files you wish to verify +# The default target `verify` verified ROOTS and its dependencies +# To lax-check instead, set `OTHERFLAGS="--lax"` on the command-line +# +# To make F* emacs mode use the settings in this file, you need to +# add the following lines to your .emacs +# +# (setq-default fstar-executable "/bin/fstar.exe") +# (setq-default fstar-smt-executable "/bin/z3") +# +# (defun my-fstar-compute-prover-args-using-make () +# "Construct arguments to pass to F* by calling make." +# (with-demoted-errors "Error when constructing arg string: %S" +# (let* ((fname (file-name-nondirectory buffer-file-name)) +# (target (concat fname "-in")) +# (argstr (car (process-lines "make" "--quiet" target)))) +# (split-string argstr)))) +# (setq fstar-subp-prover-args #'my-fstar-compute-prover-args-using-make) +# + +HACL_HOME ?= $(HOME)/.hax/hacl_home +FSTAR_BIN ?= $(shell command -v fstar.exe 1>&2 2> /dev/null && echo "fstar.exe" || echo "$(FSTAR_HOME)/bin/fstar.exe") + +CACHE_DIR ?= .cache +HINT_DIR ?= .hints + +.PHONY: all verify clean + +all: + rm -f .depend && $(MAKE) .depend + $(MAKE) verify + +# If $HACL_HOME doesn't exist, clone it +${HACL_HOME}: + mkdir -p "${HACL_HOME}" + git clone --depth 1 https://github.com/hacl-star/hacl-star.git "${HACL_HOME}" + +# By default, we process all the files in the current directory +ROOTS = $(wildcard *.fst *fsti) + +# The following is a bash script that discovers F* libraries +define FINDLIBS + # Prints a path if and only if it exists. Takes one argument: the + # path. + function print_if_exists() { + if [ -d "$$1" ]; then + echo "$$1" + fi + } + # Asks Cargo all the dependencies for the current crate or workspace, + # and extract all "root" directories for each. Takes zero argument. + function dependencies() { + cargo metadata --format-version 1 | + jq -r '.packages | .[] | .manifest_path | split("/") | .[:-1] | join("/")' + } + # Find hax libraries *around* a given path. Takes one argument: the + # path. + function find_hax_libraries_at_path() { + path="$$1" + # if there is a `proofs/fstar/extraction` subfolder, then that's a + # F* library + print_if_exists "$$path/proofs/fstar/extraction" + # Maybe the `proof-libs` folder of hax is around? + MAYBE_PROOF_LIBS=$$(realpath -q "$$path/../proof-libs/fstar") + if [ $$? -eq 0 ]; then + print_if_exists "$$MAYBE_PROOF_LIBS/core" + print_if_exists "$$MAYBE_PROOF_LIBS/rust_primitives" + fi + } + { while IFS= read path; do + find_hax_libraries_at_path "$$path" + done < <(dependencies) + } | sort -u +endef +export FINDLIBS + +FSTAR_INCLUDE_DIRS = $(HACL_HOME)/lib $(shell bash -c "$$FINDLIBS") + +FSTAR_FLAGS = --cmi \ + --warn_error -331 \ + --cache_checked_modules --cache_dir $(CACHE_DIR) \ + --already_cached "+Prims+FStar+LowStar+C+Spec.Loops+TestLib" \ + $(addprefix --include ,$(FSTAR_INCLUDE_DIRS)) + +FSTAR = $(FSTAR_BIN) $(FSTAR_FLAGS) + +.depend: $(HINT_DIR) $(CACHE_DIR) $(ROOTS) + $(info $(ROOTS)) + $(FSTAR) --cmi --dep full $(ROOTS) --extract '* -Prims -LowStar -FStar' > $@ + +include .depend + +$(HINT_DIR): + mkdir -p $@ + +$(CACHE_DIR): + mkdir -p $@ + +$(CACHE_DIR)/%.checked: | .depend $(HINT_DIR) $(CACHE_DIR) + $(FSTAR) $(OTHERFLAGS) $< $(ENABLE_HINTS) --hint_file $(HINT_DIR)/$(notdir $*).hints + +verify: $(addsuffix .checked, $(addprefix $(CACHE_DIR)/,$(ROOTS))) + +# Targets for interactive mode + +%.fst-in: + $(info $(FSTAR_FLAGS) \ + $(ENABLE_HINTS) --hint_file $(HINT_DIR)/$(basename $@).fst.hints) + +%.fsti-in: + $(info $(FSTAR_FLAGS) \ + $(ENABLE_HINTS) --hint_file $(HINT_DIR)/$(basename $@).fsti.hints) + + +# Clean targets + +SHELL=bash + +clean: + rm -rf $(CACHE_DIR)/* + rm *.fst + diff --git a/book/src/tutorial/proofs/fstar/extraction/Tutorial_src.Math.Lemmas.fst b/book/src/tutorial/proofs/fstar/extraction/Tutorial_src.Math.Lemmas.fst new file mode 100644 index 000000000..4148f70e3 --- /dev/null +++ b/book/src/tutorial/proofs/fstar/extraction/Tutorial_src.Math.Lemmas.fst @@ -0,0 +1,9 @@ +module Tutorial_src.Math.Lemmas +#set-options "--fuel 0 --ifuel 1 --z3rlimit 150" +open Core +open FStar.Mul + + +val cancel_mul_mod (a:i32) (n:i32 {v n >= 0}) : Lemma ((v a * v n) % v n == 0) +let cancel_mul_mod a n = + FStar.Math.Lemmas.cancel_mul_mod (v a) (v n) diff --git a/book/src/tutorial/proofs/fstar/extraction/Tutorial_src.fst b/book/src/tutorial/proofs/fstar/extraction/Tutorial_src.fst new file mode 100644 index 000000000..002994bfe --- /dev/null +++ b/book/src/tutorial/proofs/fstar/extraction/Tutorial_src.fst @@ -0,0 +1,82 @@ +module Tutorial_src +#set-options "--fuel 0 --ifuel 1 --z3rlimit 15" +open Core +open FStar.Mul + +type t_F3 = + | F3_E1 : t_F3 + | F3_E2 : t_F3 + | F3_E3 : t_F3 + +let t_F3_cast_to_repr (x: t_F3) : isize = + match x with + | F3_E1 -> isz 0 + | F3_E2 -> isz 1 + | F3_E3 -> isz 3 + +unfold +let t_FieldElement = i32 + +let v_BARRETT_MULTIPLIER: i64 = 20159L + +let v_BARRETT_R: i64 = 67108864L + +let v_BARRETT_SHIFT: i64 = 26L + +let v_FIELD_MODULUS: i32 = 3329l + +let v_Q: u16 = 2347us + +let barrett_reduce (value: i32) + : Prims.Pure i32 + (requires + (Core.Convert.f_from value <: i64) >=. (Core.Ops.Arith.Neg.neg v_BARRETT_R <: i64) && + (Core.Convert.f_from value <: i64) <=. v_BARRETT_R) + (ensures + fun result -> + let result:i32 = result in + result >. (Core.Ops.Arith.Neg.neg v_FIELD_MODULUS <: i32) && result <. v_FIELD_MODULUS && + (result %! v_FIELD_MODULUS <: i32) =. (value %! v_FIELD_MODULUS <: i32)) = + let t:i64 = (Core.Convert.f_from value <: i64) *! v_BARRETT_MULTIPLIER in + let t:i64 = t +! (v_BARRETT_R >>! 1l <: i64) in + let quotient:i64 = t >>! v_BARRETT_SHIFT in + let quotient:i32 = cast (quotient <: i64) <: i32 in + let sub:i32 = quotient *! v_FIELD_MODULUS in + let _:Prims.unit = Tutorial_src.Math.Lemmas.cancel_mul_mod quotient 3329l in + value -! sub + +let decrypt (ciphertext key: u32) : u32 = ciphertext ^. key + +let encrypt (plaintext key: u32) : u32 = plaintext ^. key + +let encrypt_decrypt_identity (key plaintext: u32) + : Lemma (requires true) + (ensures (decrypt (encrypt plaintext key <: u32) key <: u32) =. plaintext) = () + +let square (x: u8) : u8 = x *! x + +let square_ensures (x: u8) + : Prims.Pure u8 + (requires x <. 16uy) + (ensures + fun result -> + let result:u8 = result in + result >=. x) = x *! x + +let square_option (x: u8) : Core.Option.t_Option u8 = + if x >=. 16uy + then Core.Option.Option_None <: Core.Option.t_Option u8 + else Core.Option.Option_Some (x *! x) <: Core.Option.t_Option u8 + +let square_requires (x: u8) : Prims.Pure u8 (requires x <. 16uy) (fun _ -> Prims.l_True) = x *! x + +type t_F = { f_v:f_v: u16{f_v <. v_Q} } + +[@@ FStar.Tactics.Typeclasses.tcinstance] +let impl: Core.Ops.Arith.t_Add t_F t_F = + { + f_Output = t_F; + f_add_pre = (fun (self: t_F) (rhs: t_F) -> true); + f_add_post = (fun (self: t_F) (rhs: t_F) (out: t_F) -> true); + f_add = fun (self: t_F) (rhs: t_F) -> { f_v = (self.f_v +! rhs.f_v <: u16) %! v_Q } <: t_F + } diff --git a/book/src/tutorial/properties.md b/book/src/tutorial/properties.md new file mode 100644 index 000000000..5e1a438ab --- /dev/null +++ b/book/src/tutorial/properties.md @@ -0,0 +1,106 @@ +# Proving properties + +In the last chapter, we proved one property on the `square` function: +panic freedom. After adding a precondition, the signature of the +`square` function was `x:u8 -> Pure u8 (requires x <. 16uy) (ensures fun _ -> True)`. + +This contract stipulates that, given a small input, the function will +_return a value_: it will not panic or diverge. We could enrich the +contract of `square` with a post-condition about the fact it is a +increasing function: + +```rust,noplaypen +{{#include sources.rs:square_ensures}} +``` + +```ocaml +{{#include Sources.fst:square_ensures}} +``` + +Such a simple post-condition is automatically proven by F\*. The +properties of our `square` function are not fasinating. Let's study a +more interesting example: [Barrett reduction](https://en.wikipedia.org/wiki/Barrett_reduction). + +## A concrete example of contract: Barrett reduction + +While the correctness of `square` is obvious, the Barrett reduction is +not. + +Given `value` a field element (a `i32` whose absolute value is at most +`BARRET_R`), the function `barrett_reduce` defined below computes +`result` such that: + +- `result ≡ value (mod FIELD_MODULUS)`; +- the absolute value of `result` is bound as follows: + `|result| < FIELD_MODULUS`. + +It is easy to write this contract directly as `hax::requires` and +`hax::ensures` annotations, as shown in the snippet below. + +```rust,noplaypen +{{#include sources.rs:barrett}} +``` + +```ocaml +{{#include Sources.fst:barrett}} +``` + + + +Before returning, a lemma may have to be called in F* to prove the correctness +of the reduction. +The lemma is `Math.Lemmas.cancel_mul_mod (v quotient) 3329;`, which establishes +that `(quotient * 3329) % 3329` is zero. +With the help of that one lemma, F\* is able to prove the +reduction computes the expected result. +(We may expose lemmas like this to call from Rust directly in future.) + +This Barrett reduction examples is taken from +[libcrux](https://github.com/cryspen/libcrux/tree/main)'s proof of +Kyber which is using hax and F\*. + +This example showcases an **intrinsic proof**: the function +`barrett_reduce` not only computes a value, but it also ship a proof +that the post-condition holds. The pre-condition and post-condition +gives the function a formal specification, which is useful both for +further formal verification and for documentation purposes. + +## Extrinsic properties with lemmas + +Consider the `encrypt` and `decrypt` functions below. Those functions +have no precondition, don't have particularly interesting properties +individually. However, the compostion of the two yields an useful +property: encrypting a ciphertext and decrypting the result with a +same key produces the ciphertext again. `|c| decrypt(c, key)` is the +inverse of `|p| encrypt(p, key)`. + +```rust,noplaypen +{{#include sources.rs:encrypt_decrypt}} +``` + +```ocaml +{{#include Sources.fst:encrypt_decrypt}} +``` + +In this situation, adding a pre- or a post-condition to either +`encrypt` or `decrypt` is not useful: we want to state our inverse +property about both of them. Better, we want this property to be +stated directly in Rust: just as with pre and post-conditions, the +Rust souces should clearly state what is to be proven. + +To this end, Hax provides a macro `lemma`. Below, the Rust function +`encrypt_decrypt_identity` takes a key and a plaintext, and then +states the inverse property. The body is empty: the details of the +proof itself are not relevant, at this stage, we only care about the +statement. The proof will be completed manually in the proof +assistant. + +```rust,noplaypen +{{#include sources.rs:encrypt_decrypt_identity}} +``` + +```ocaml +{{#include Sources.fst:encrypt_decrypt_identity}} +``` diff --git a/book/src/tutorial/readme.md b/book/src/tutorial/readme.md new file mode 100644 index 000000000..dbe20068d --- /dev/null +++ b/book/src/tutorial/readme.md @@ -0,0 +1,15 @@ +# Tutorial + +This tutorial is a guide for formally verifying properties about Rust +programs using the hax toolchain. hax is a tool that translates Rust +programs to various formal programming languages. + +The formal programming languages we target are called *backends*. Some +of them, e.g. [F*](https://fstar-lang.org/) or +[Coq](https://coq.inria.fr/), are general purpose formal programming +languages. Others are specialized tools: +[ProVerif](https://bblanche.gitlabpages.inria.fr/proverif/) is +dedicated to proving properties about protocols. + +This tutorial focuses on proving properties with the +[F* programming language](https://fstar-lang.org/). diff --git a/book/src/tutorial/sources.rs b/book/src/tutorial/sources.rs new file mode 100644 index 000000000..74bd51b6f --- /dev/null +++ b/book/src/tutorial/sources.rs @@ -0,0 +1,138 @@ +// ANCHOR: square +fn square(x: u8) -> u8 { + x * x +} +// ANCHOR_END: square + +// ANCHOR: square_option +fn square_option(x: u8) -> Option { + if x >= 16 { + None + } else { + Some(x * x) + } +} +// ANCHOR_END: square_option + +// ANCHOR: square_requires +#[hax_lib::requires(x < 16)] +fn square_requires(x: u8) -> u8 { + x * x +} +// ANCHOR_END: square_requires + +// ANCHOR: square_ensures +#[hax_lib::requires(x < 16)] +#[hax_lib::ensures(|result| result >= x)] +fn square_ensures(x: u8) -> u8 { + x * x +} +// ANCHOR_END: square_ensures + +// ANCHOR: barrett +type FieldElement = i32; +const FIELD_MODULUS: i32 = 3329; +const BARRETT_SHIFT: i64 = 26; +const BARRETT_R: i64 = 0x4000000; // 2^26 +const BARRETT_MULTIPLIER: i64 = 20159; // ⌊(BARRETT_R / FIELD_MODULUS) + 1/2⌋ + +#[hax_lib::requires((i64::from(value) >= -BARRETT_R && i64::from(value) <= BARRETT_R))] +#[hax_lib::ensures(|result| result > -FIELD_MODULUS && result < FIELD_MODULUS + && result % FIELD_MODULUS == value % FIELD_MODULUS)] +fn barrett_reduce(value: i32) -> i32 { + let t = i64::from(value) * BARRETT_MULTIPLIER; + let t = t + (BARRETT_R >> 1); + + let quotient = t >> BARRETT_SHIFT; + let quotient = quotient as i32; + + let sub = quotient * FIELD_MODULUS; + + // Here a lemma to prove that `(quotient * 3329) % 3329 = 0` + // may have to be called in F*. + + value - sub +} +// ANCHOR_END: barrett + +#[hax_lib::exclude] +pub(crate) mod math { + pub(crate) mod lemmas { + pub(crate) fn cancel_mul_mod(a: i32, n: i32) {} + } +} + +// ANCHOR: encrypt_decrypt +fn encrypt(plaintext: u32, key: u32) -> u32 { + plaintext ^ key +} + +fn decrypt(ciphertext: u32, key: u32) -> u32 { + ciphertext ^ key +} +// ANCHOR_END: encrypt_decrypt + +// ANCHOR: encrypt_decrypt_identity +#[hax_lib::lemma] +#[hax_lib::requires(true)] +fn encrypt_decrypt_identity( + key: u32, + plaintext: u32, +) -> Proof<{ decrypt(encrypt(plaintext, key), key) == plaintext }> { +} +// ANCHOR_END: encrypt_decrypt_identity + +// ANCHOR: F3 +enum F3 { + E1, + E2, + E3, +} +// ANCHOR_END: F3 + +// ANCHOR: F +pub const Q: u16 = 2347; + +#[hax_lib::attributes] +pub struct F { + #[hax_lib::refine(v < Q)] + pub v: u16, +} +// ANCHOR_END: F + +// ANCHOR: AddF +use core::ops::Add; + +impl Add for F { + type Output = Self; + fn add(self, rhs: Self) -> Self { + Self { + v: (self.v + rhs.v) % Q, + } + } +} +// ANCHOR_END: AddF + +// fn is_divisible_by(lhs: u32, rhs: u32) -> bool { +// if rhs == 0 { +// return false; +// } + +// lhs % rhs == 0 +// } + +// fn encrypt(plaintext: u32, key: u32) -> u32 { +// plaintext ^ key +// } + +// fn decrypt(ciphertext: u32, key: u32) -> u32 { +// ciphertext ^ key +// } + +// #[hax_lib::lemma] +// #[hax_lib::requires(true)] +// fn encrypt_decrypt_identity( +// plaintext: u32, +// key: u32, +// ) -> Proof<{ decrypt(encrypt(plaintext, key), key) == plaintext }> { +// } diff --git a/cli/driver/Cargo.toml b/cli/driver/Cargo.toml index 0f33501ff..097f0911a 100644 --- a/cli/driver/Cargo.toml +++ b/cli/driver/Cargo.toml @@ -21,18 +21,11 @@ serde.workspace = true serde_json.workspace = true clap.workspace = true colored.workspace = true -hax-frontend-exporter.workspace = true -hax-cli-options.workspace = true -hax-cli-options-engine.workspace = true +hax-frontend-exporter = {workspace = true, features = ["rustc"]} +hax-types = {workspace = true, features = ["rustc"]} hax-frontend-exporter-options.workspace = true -hax-lint.workspace = true -hax-diagnostics.workspace = true hax-lib-macros-types.workspace = true itertools.workspace = true -which.workspace = true -inquire = "0.6" -const_format = "0.2" tracing.workspace = true tracing-subscriber.workspace = true tracing-tree.workspace = true -hax-phase-debug-webapp.workspace = true diff --git a/cli/driver/src/callbacks_wrapper.rs b/cli/driver/src/callbacks_wrapper.rs index 3fa124373..5a5bc28a1 100644 --- a/cli/driver/src/callbacks_wrapper.rs +++ b/cli/driver/src/callbacks_wrapper.rs @@ -1,5 +1,4 @@ -use const_format::formatcp; -use hax_cli_options::{Command, ENV_VAR_OPTIONS_FRONTEND}; +use hax_types::cli_options::{Command, Options, ENV_VAR_OPTIONS_FRONTEND}; use rustc_driver::{Callbacks, Compilation}; use rustc_interface::{interface, Queries}; @@ -9,14 +8,14 @@ use rustc_span::symbol::Symbol; /// configuration in the `config` phase of rustc pub struct CallbacksWrapper<'a> { pub sub: &'a mut (dyn Callbacks + Send + 'a), - pub options: hax_cli_options::Options, + pub options: Options, } impl<'a> Callbacks for CallbacksWrapper<'a> { fn config(&mut self, config: &mut interface::Config) { let options = self.options.clone(); - config.parse_sess_created = Some(Box::new(move |parse_sess| { + config.psess_created = Some(Box::new(move |parse_sess| { parse_sess.env_depinfo.get_mut().insert(( - Symbol::intern(hax_cli_options::ENV_VAR_OPTIONS_FRONTEND), + Symbol::intern(ENV_VAR_OPTIONS_FRONTEND), Some(Symbol::intern(&serde_json::to_string(&options).unwrap())), )); })); diff --git a/cli/driver/src/driver.rs b/cli/driver/src/driver.rs index 5120911ec..66911e338 100644 --- a/cli/driver/src/driver.rs +++ b/cli/driver/src/driver.rs @@ -30,18 +30,13 @@ mod exporter; use std::collections::HashSet; use exporter::ExtractionCallbacks; -use hax_lint::Type; - -mod linter; -use linter::LinterCallbacks; mod callbacks_wrapper; mod features; use callbacks_wrapper::*; use features::*; -use const_format::formatcp; -use hax_cli_options::{BackendOptions, Command, ExporterCommand, ENV_VAR_OPTIONS_FRONTEND}; +use hax_types::cli_options::{BackendOptions, Command, ENV_VAR_OPTIONS_FRONTEND}; use rustc_driver::{Callbacks, Compilation}; use rustc_interface::{interface, Queries}; @@ -65,6 +60,11 @@ fn setup_logging() { }; let subscriber = tracing_subscriber::Registry::default() .with(tracing_subscriber::EnvFilter::from_default_env()) + .with( + tracing_subscriber::fmt::layer() + .with_file(true) + .with_line_number(true), + ) .with( tracing_tree::HierarchicalLayer::new(2) .with_ansi(enable_colors) @@ -78,12 +78,12 @@ const HAX_VANILLA_RUSTC: &str = "HAX_VANILLA_RUSTC"; fn main() { setup_logging(); - let options: hax_cli_options::Options = - serde_json::from_str(&std::env::var(ENV_VAR_OPTIONS_FRONTEND).expect(&formatcp!( + let options: hax_types::cli_options::Options = + serde_json::from_str(&std::env::var(ENV_VAR_OPTIONS_FRONTEND).expect(&format!( "Cannot find environnement variable {}", ENV_VAR_OPTIONS_FRONTEND ))) - .expect(&formatcp!( + .expect(&format!( "Invalid value for the environnement variable {}", ENV_VAR_OPTIONS_FRONTEND )); @@ -122,24 +122,11 @@ fn main() { let translate_package = !vanilla_rustc && !is_build_script && (options.deps || is_primary_package); let mut callbacks: Box = if translate_package { - match &options.command { - Some(Command::ExporterCommand(command)) => Box::new(exporter::ExtractionCallbacks { - inline_macro_calls: options.inline_macro_calls.clone(), - command: command.clone(), - macro_calls: std::collections::HashMap::new(), - }), - Some(Command::LintCommand(command)) => { - let ltype = match command { - hax_cli_options::LinterCommand::Hacspec => Type::Hacspec, - hax_cli_options::LinterCommand::Rust => Type::Rust, - }; - Box::new(LinterCallbacks::new(ltype)) - } - None => { - // hacspec lint - Box::new(LinterCallbacks::new(Type::Rust)) - } - } + Box::new(exporter::ExtractionCallbacks { + inline_macro_calls: options.inline_macro_calls.clone(), + body_types: options.command.body_kinds(), + macro_calls: std::collections::HashMap::new(), + }) } else { struct CallbacksNoop; impl Callbacks for CallbacksNoop {} @@ -166,10 +153,9 @@ fn main() { hax_lib_macros_types::HAX_CFG_OPTION_NAME.into(), ]) .chain(match &options.command { - Some(Command::ExporterCommand(ExporterCommand::Backend(BackendOptions { - backend, - .. - }))) => vec!["--cfg".into(), format!("hax_backend_{backend}")], + Command::Backend(BackendOptions { backend, .. }) => { + vec!["--cfg".into(), format!("hax_backend_{backend}")] + } _ => vec![], }) .chain(features.into_iter().map(|s| format!("-Zcrate-attr={}", s))) @@ -179,13 +165,14 @@ fn main() { let mut callbacks = CallbacksWrapper { sub: &mut *callbacks, - options: hax_cli_options::Options { - force_cargo_build: if translate_package { + options: { + let mut options = options.clone(); + options.force_cargo_build = if translate_package { options.force_cargo_build } else { - hax_cli_options::ForceCargoBuild::default() - }, - ..options + hax_types::cli_options::ForceCargoBuild::default() + }; + options }, }; diff --git a/cli/driver/src/exporter.rs b/cli/driver/src/exporter.rs index 948fbf5b5..8b3d54a7e 100644 --- a/cli/driver/src/exporter.rs +++ b/cli/driver/src/exporter.rs @@ -1,7 +1,7 @@ -use hax_cli_options::{Backend, PathOrDash, ENV_VAR_OPTIONS_FRONTEND}; use hax_frontend_exporter; use hax_frontend_exporter::state::{ExportedSpans, LocalContextS}; use hax_frontend_exporter::SInto; +use hax_types::cli_options::{Backend, PathOrDash, ENV_VAR_OPTIONS_FRONTEND}; use rustc_driver::{Callbacks, Compilation}; use rustc_interface::interface; use rustc_interface::{interface::Compiler, Queries}; @@ -11,61 +11,29 @@ use rustc_middle::{ thir, thir::{Block, BlockId, Expr, ExprId, ExprKind, Pat, PatKind, Stmt, StmtId, StmtKind, Thir}, }; -use rustc_session::parse::ParseSess; use rustc_span::symbol::Symbol; use serde::Serialize; use std::cell::RefCell; use std::collections::{HashMap, HashSet}; use std::rc::Rc; -fn report_diagnostics( - output: &hax_cli_options_engine::Output, - session: &rustc_session::Session, - mapping: &Vec<(hax_frontend_exporter::Span, rustc_span::Span)>, -) { - for d in &output.diagnostics { - use hax_diagnostics::*; - session.span_hax_err(d.convert(mapping).into()); - } -} - -fn write_files( - output: &hax_cli_options_engine::Output, - session: &rustc_session::Session, - backend: hax_cli_options::Backend, -) { - let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap(); - let manifest_dir = std::path::Path::new(&manifest_dir); - let relative_path: std::path::PathBuf = ["proofs", format!("{backend}").as_str(), "extraction"] - .iter() - .collect(); - let out_dir = manifest_dir.join(&relative_path); - for file in output.files.clone() { - let path = out_dir.join(&file.path); - std::fs::create_dir_all(&path.parent().unwrap()).unwrap(); - session.note_without_error(format!("Writing file {:#?}", path)); - std::fs::write(&path, file.contents).unwrap_or_else(|e| { - session.fatal(format!( - "Unable to write to file {:#?}. Error: {:#?}", - path, e - )) - }) - } -} - type ThirBundle<'tcx> = (Rc>, ExprId); /// Generates a dummy THIR body with an error literal as first expression -fn dummy_thir_body<'tcx>(tcx: TyCtxt<'tcx>, span: rustc_span::Span) -> ThirBundle<'tcx> { +fn dummy_thir_body<'tcx>( + tcx: TyCtxt<'tcx>, + span: rustc_span::Span, + guar: rustc_errors::ErrorGuaranteed, +) -> ThirBundle<'tcx> { use rustc_middle::thir::*; - let ty = tcx.mk_ty_from_kind(rustc_type_ir::sty::TyKind::Never); + let ty = tcx.mk_ty_from_kind(rustc_type_ir::TyKind::Never); let mut thir = Thir::new(BodyTy::Const(ty)); - const ERR_LITERAL: &'static rustc_hir::Lit = &rustc_span::source_map::Spanned { - node: rustc_ast::ast::LitKind::Err, + let lit_err = tcx.hir_arena.alloc(rustc_span::source_map::Spanned { + node: rustc_ast::ast::LitKind::Err(guar), span: rustc_span::DUMMY_SP, - }; + }); let expr = thir.exprs.push(Expr { kind: ExprKind::Literal { - lit: ERR_LITERAL, + lit: lit_err, neg: false, }, ty, @@ -127,15 +95,15 @@ fn precompute_local_thir_bodies<'tcx>( .filter(|ldid| hir.maybe_body_owned_by(*ldid).is_some()) .map(|ldid| { tracing::debug!("⏳ Type-checking THIR body for {:#?}", ldid); - let span = hir.span(hir.local_def_id_to_hir_id(ldid)); + let span = hir.span(tcx.local_def_id_to_hir_id(ldid)); let (thir, expr) = match tcx.thir_body(ldid) { Ok(x) => x, Err(e) => { - tcx.sess.span_err( + let guar = tcx.dcx().span_err( span, "While trying to reach a body's THIR defintion, got a typechecking error.", ); - return (ldid, dummy_thir_body(tcx, span)); + return (ldid, dummy_thir_body(tcx, span, guar)); } }; let thir = match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { @@ -143,8 +111,8 @@ fn precompute_local_thir_bodies<'tcx>( })) { Ok(x) => x, Err(e) => { - tcx.sess.span_err(span, format!("The THIR body of item {:?} was stolen.\nThis is not supposed to happen.\nThis is a bug in Hax's frontend.\nThis is discussed in issue https://github.com/hacspec/hax/issues/27.\nPlease comment this issue if you see this error message!", ldid)); - return (ldid, dummy_thir_body(tcx, span)); + let guar = tcx.dcx().span_err(span, format!("The THIR body of item {:?} was stolen.\nThis is not supposed to happen.\nThis is a bug in Hax's frontend.\nThis is discussed in issue https://github.com/hacspec/hax/issues/27.\nPlease comment this issue if you see this error message!", ldid)); + return (ldid, dummy_thir_body(tcx, span, guar)); } }; tracing::debug!("✅ Type-checked THIR body for {:#?}", ldid); @@ -213,69 +181,12 @@ fn collect_macros( v.macro_calls } -const ENGINE_BINARY_NAME: &str = "hax-engine"; -const ENGINE_BINARY_NOT_FOUND: &str = const_format::formatcp!( - "The binary [{}] was not found in your [PATH].", - ENGINE_BINARY_NAME, -); - -/// Dynamically looks for binary [ENGINE_BINARY_NAME]. First, we -/// check whether [HAX_ENGINE_BINARY] is set, and use that if it -/// is. Then, we try to find [ENGINE_BINARY_NAME] in PATH. If not -/// found, detect whether nodejs is available, download the JS-compiled -/// engine and use it. -use std::process; -fn find_hax_engine() -> process::Command { - use which::which; - - std::env::var("HAX_ENGINE_BINARY") - .ok() - .map(|name| process::Command::new(name)) - .or_else(|| { - which(ENGINE_BINARY_NAME) - .ok() - .map(|name| process::Command::new(name)) - }) - .or_else(|| { - which("node").ok().and_then(|_| { - if let Ok(true) = inquire::Confirm::new(&format!( - "{} Should I try to download it from GitHub?", - ENGINE_BINARY_NOT_FOUND, - )) - .with_default(true) - .prompt() - { - let cmd = process::Command::new("node"); - let engine_js_path: String = - panic!("TODO: Downloading from GitHub is not supported yet."); - cmd.arg(engine_js_path); - Some(cmd) - } else { - None - } - }) - }) - .unwrap_or_else(|| { - fn is_opam_setup_correctly() -> bool { - std::env::var("OPAM_SWITCH_PREFIX").is_ok() - } - use colored::Colorize; - eprintln!("\n{}\n{}\n\n{} {}\n", - &ENGINE_BINARY_NOT_FOUND, - "Please make sure the engine is installed and is in PATH!", - "Hint: With OPAM, `eval $(opam env)` is necessary for OPAM binaries to be in PATH: make sure to run `eval $(opam env)` before running `cargo hax`.".bright_black(), - format!("(diagnostics: {})", if is_opam_setup_correctly() { "opam seems okay ✓" } else {"opam seems not okay ❌"}).bright_black() - ); - panic!("{}", &ENGINE_BINARY_NOT_FOUND) - }) -} - /// Callback for extraction #[derive(Debug, Clone, Serialize)] pub(crate) struct ExtractionCallbacks { - pub inline_macro_calls: Vec, - pub command: hax_cli_options::ExporterCommand, + pub inline_macro_calls: Vec, pub macro_calls: HashMap, + pub body_types: Vec, } impl From for hax_frontend_exporter_options::Options { @@ -298,7 +209,7 @@ impl Callbacks for ExtractionCallbacks { .into_iter() .map(|(k, v)| { use hax_frontend_exporter::*; - let sess = compiler.session(); + let sess = &compiler.sess; ( translate_span(k, sess), translate_span(argument_span_of_mac_call(&v), sess), @@ -315,181 +226,74 @@ impl Callbacks for ExtractionCallbacks { use std::ops::{Deref, DerefMut}; queries.global_ctxt().unwrap().enter(|tcx| { - use hax_cli_options::ExporterCommand; - match self.command.clone() { - ExporterCommand::JSON { - output_file, - mut kind, - include_extra, - } => { - struct Driver<'tcx> { - options: hax_frontend_exporter_options::Options, - macro_calls: - HashMap, - tcx: TyCtxt<'tcx>, - output_file: PathOrDash, - include_extra: bool, - } - impl<'tcx> Driver<'tcx> { - fn to_json(self) { - let (_, def_ids, impl_infos, converted_items) = convert_thir::( - &self.options, - self.macro_calls.clone(), - self.tcx, - ); + use hax_frontend_exporter::ThirBody; + use hax_types::cli_options::Command; + use rustc_session::config::CrateType; + use serde::{Deserialize, Serialize}; + use std::fs::File; + use std::io::BufWriter; - let dest = self.output_file.open_or_stdout(); - (if self.include_extra { - serde_json::to_writer( - dest, - &hax_cli_options_engine::WithDefIds { - def_ids, - impl_infos, - items: converted_items, - }, - ) - } else { - serde_json::to_writer(dest, &converted_items) - }) - .unwrap() - } - } - let driver = Driver { - options: self.clone().into(), - macro_calls: self.macro_calls.clone(), - tcx, - output_file, - include_extra, - }; - mod from { - pub use hax_cli_options::ExportBodyKind::{ - MirBuilt as MB, MirConst as MC, Thir as T, - }; - } - mod to { - pub type T = hax_frontend_exporter::ThirBody; - pub type MB = - hax_frontend_exporter::MirBody; - pub type MC = - hax_frontend_exporter::MirBody; - } - kind.sort(); - kind.dedup(); - match kind.as_slice() { - [from::MB] => driver.to_json::(), - [from::MC] => driver.to_json::(), - [from::T] => driver.to_json::(), - [from::MB, from::MC] => driver.to_json::<(to::MB, to::MC)>(), - [from::T, from::MB] => driver.to_json::<(to::MB, to::T)>(), - [from::T, from::MC] => driver.to_json::<(to::MC, to::T)>(), - [from::T, from::MB, from::MC] => { - driver.to_json::<(to::MB, (to::MC, to::T))>() - } - [] => driver.to_json::<()>(), - _ => panic!("Unsupported kind {:#?}", kind), - } - } - ExporterCommand::Backend(backend) => { - if matches!(backend.backend, Backend::Easycrypt | Backend::ProVerif(..)) { - eprintln!( - "⚠️ Warning: Experimental backend \"{}\" is work in progress.", - backend.backend - ) - } + use std::path::PathBuf; - let (spans, _def_ids, impl_infos, converted_items) = - convert_thir(&self.clone().into(), self.macro_calls.clone(), tcx); + let opts = &compiler.sess.opts; + let externs: Vec<_> = opts + .externs + .iter() + .flat_map(|(_, ext)| match &ext.location { + rustc_session::config::ExternLocation::ExactPaths(set) => set + .iter() + .map(|cp| cp.canonicalized()) + .collect::>() + .into_iter(), + _ => vec![].into_iter(), + }) + .map(|path| path.with_extension("haxmeta")) + .collect(); + + let cg_metadata = opts.cg.metadata[0].clone(); + let crate_name = opts.crate_name.clone().unwrap(); + + let output_dir = compiler.sess.io.output_dir.clone().unwrap(); + let haxmeta_path = output_dir.join(format!("{crate_name}-{cg_metadata}.haxmeta",)); - let engine_options = hax_cli_options_engine::EngineOptions { - backend: backend.clone(), - input: converted_items, + let mut file = BufWriter::new(File::create(&haxmeta_path).unwrap()); + + use hax_types::driver_api::{with_kind_type, HaxMeta}; + with_kind_type!( + self.body_types.clone(), + || { + let (spans, def_ids, impl_infos, items) = + convert_thir(&self.clone().into(), self.macro_calls.clone(), tcx); + let haxmeta: HaxMeta = HaxMeta { + crate_name, + cg_metadata, + externs, impl_infos, + items, + def_ids, }; - let mut engine_subprocess = find_hax_engine() - .stdin(std::process::Stdio::piped()) - .stdout(std::process::Stdio::piped()) - .spawn() - .map_err(|e| { - if let std::io::ErrorKind::NotFound = e.kind() { - panic!( - "The binary [{}] was not found in your [PATH].", - ENGINE_BINARY_NAME - ) - } - e - }) - .unwrap(); + haxmeta.write(&mut file); + } + ); - serde_json::to_writer::<_, hax_cli_options_engine::EngineOptions>( - std::io::BufWriter::new( - engine_subprocess - .stdin - .as_mut() - .expect("Could not write on stdin"), - ), - &engine_options, - ) - .unwrap(); + let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap(); + let manifest_dir = std::path::Path::new(&manifest_dir); - let out = engine_subprocess.wait_with_output().unwrap(); - let session = compiler.session(); - if !out.status.success() { - session.fatal(format!( - "{} exited with non-zero code {}\nstdout: {}\n stderr: {}", - ENGINE_BINARY_NAME, - out.status.code().unwrap_or(-1), - String::from_utf8(out.stdout).unwrap(), - String::from_utf8(out.stderr).unwrap(), - )); - return Compilation::Stop; - } - let output: hax_cli_options_engine::Output = - serde_json::from_slice(out.stdout.as_slice()).unwrap_or_else(|_| { - panic!( - "{} outputed incorrect JSON {}", - ENGINE_BINARY_NAME, - String::from_utf8(out.stdout).unwrap() - ) - }); - let options_frontend = - hax_frontend_exporter_options::Options::from(self.clone()); - let state = - hax_frontend_exporter::state::State::new(tcx, options_frontend.clone()); - report_diagnostics( - &output, - &session, - &spans - .into_iter() - .map(|span| (span.sinto(&state), span.clone())) - .collect(), - ); - if backend.dry_run { - serde_json::to_writer(std::io::BufWriter::new(std::io::stdout()), &output) - .unwrap() - } else { - write_files(&output, &session, backend.backend); - } - if let Some(debug_json) = &output.debug_json { - use hax_cli_options::DebugEngineMode; - match backend.debug_engine { - Some(DebugEngineMode::Interactive) => { - eprintln!("----------------------------------------------"); - eprintln!("----------------------------------------------"); - eprintln!("----------------------------------------------"); - eprintln!("-- Engine debug mode. Press CTRL+C to exit. --"); - eprintln!("----------------------------------------------"); - eprintln!("----------------------------------------------"); - eprintln!("----------------------------------------------"); - hax_phase_debug_webapp::run(|| debug_json.clone()) - } - Some(DebugEngineMode::File(file)) if !backend.dry_run => { - println!("{}", debug_json) - } - _ => (), - } - } - } + let data = hax_types::driver_api::EmitHaxMetaMessage { + manifest_dir: manifest_dir.to_path_buf(), + working_dir: opts + .working_dir + .to_path(rustc_span::FileNameDisplayPreference::Local) + .to_path_buf(), + path: haxmeta_path, }; + eprintln!( + "{}{}", + hax_types::driver_api::HAX_DRIVER_STDERR_PREFIX, + &serde_json::to_string(&hax_types::driver_api::HaxDriverMessage::EmitHaxMeta(data)) + .unwrap() + ); + Compilation::Stop }) } diff --git a/cli/driver/src/features.rs b/cli/driver/src/features.rs index 8a2d65a1f..9d0aa3a5a 100644 --- a/cli/driver/src/features.rs +++ b/cli/driver/src/features.rs @@ -78,7 +78,7 @@ impl Features { } /// Runs Rustc with a driver that only collects which unstable /// Rustc features are enabled - pub fn detect(options: &hax_cli_options::Options, rustc_args: &Vec) -> Self { + pub fn detect(options: &hax_types::cli_options::Options, rustc_args: &Vec) -> Self { struct CollectFeatures { features: Features, } @@ -102,7 +102,7 @@ impl Features { let mut callbacks = CollectFeatures { features: Features::default(), }; - let success = rustc_driver::catch_with_exit_code(|| { + let exit_code = rustc_driver::catch_with_exit_code(|| { rustc_driver::RunCompiler::new( &rustc_args, &mut CallbacksWrapper { @@ -111,7 +111,10 @@ impl Features { }, ) .run() - }) == 0; + }); + if exit_code != 0 { + std::process::exit(exit_code); + } callbacks.features.clone() } @@ -132,11 +135,9 @@ impl Features { .unwrap(); let stderr = &std::str::from_utf8(&output.stderr).unwrap(); serde_json::from_str(stderr).unwrap_or_else(|e| { - let stdout = &std::str::from_utf8(&output.stdout).unwrap(); - panic!( - "[detect_forking] could not parse `stdout`, got error `{e}`\n\n### STDERR{}\n\n### STDOUT{}", - stderr, stdout - ); + eprintln!("{}", stderr); + tracing::error!("rustc emitted an error, aborting hax custom driver."); + std::process::exit(1); }) } } diff --git a/cli/driver/src/linter.rs b/cli/driver/src/linter.rs deleted file mode 100644 index ba82517f8..000000000 --- a/cli/driver/src/linter.rs +++ /dev/null @@ -1,39 +0,0 @@ -use hax_lint::Type; -use rustc_driver::{Callbacks, Compilation}; -use rustc_interface::{ - interface::{self, Compiler}, - Queries, -}; - -pub(crate) struct LinterCallbacks { - ltype: Type, -} - -impl LinterCallbacks { - pub(crate) fn new(ltype: Type) -> Self { - Self { ltype } - } -} - -impl Callbacks for LinterCallbacks { - fn after_crate_root_parsing<'tcx>( - &mut self, - _compiler: &Compiler, - queries: &'tcx Queries<'tcx>, - ) -> Compilation { - Compilation::Continue - } - fn after_expansion<'tcx>( - &mut self, - compiler: &Compiler, - queries: &'tcx Queries<'tcx>, - ) -> Compilation { - let session = compiler.session(); - queries - .global_ctxt() - .unwrap() - .enter(|tcx| hax_lint::Linter::register(tcx, session, self.ltype)); - - Compilation::Continue - } -} diff --git a/cli/options/Cargo.toml b/cli/options/Cargo.toml deleted file mode 100644 index f302e3f18..000000000 --- a/cli/options/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "hax-cli-options" -version.workspace = true -authors.workspace = true -license.workspace = true -homepage.workspace = true -edition.workspace = true -repository.workspace = true -readme.workspace = true -build = "build.rs" -description = "The CLI options read by the `cargo-hax` binary." - -[dependencies] -serde.workspace = true -serde_json.workspace = true -schemars.workspace = true -clap.workspace = true -hax-frontend-exporter-options.workspace = true -path-clean = "1.0.1" diff --git a/cli/options/engine/src/lib.rs b/cli/options/engine/src/lib.rs deleted file mode 100644 index d48cc1e8c..000000000 --- a/cli/options/engine/src/lib.rs +++ /dev/null @@ -1,40 +0,0 @@ -use hax_cli_options::*; -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; - -type ThirBody = hax_frontend_exporter::ThirBody; - -#[derive(JsonSchema, Debug, Clone, Serialize, Deserialize)] -pub struct EngineOptions { - pub backend: BackendOptions, - pub input: Vec>, - pub impl_infos: Vec<( - hax_frontend_exporter::DefId, - hax_frontend_exporter::ImplInfos, - )>, -} - -#[derive(JsonSchema, Debug, Clone, Serialize, Deserialize)] -pub struct File { - pub path: String, - pub contents: String, -} - -#[derive(JsonSchema, Debug, Clone, Serialize, Deserialize)] -pub struct Output { - pub diagnostics: Vec>>, - pub files: Vec, - pub debug_json: Option, -} - -// This is located here for dependency reason, but this is not related -// to the engine (yet?). -#[derive(JsonSchema, Debug, Clone, Serialize, Deserialize)] -pub struct WithDefIds { - pub def_ids: Vec, - pub impl_infos: Vec<( - hax_frontend_exporter::DefId, - hax_frontend_exporter::ImplInfos, - )>, - pub items: Vec>, -} diff --git a/cli/subcommands/Cargo.toml b/cli/subcommands/Cargo.toml index 0f8e453f3..7efc93be4 100644 --- a/cli/subcommands/Cargo.toml +++ b/cli/subcommands/Cargo.toml @@ -18,10 +18,6 @@ name = "cargo-hax" path = "src/json_schema.rs" name = "hax-export-json-schemas" -[[bin]] -path = "src/pretty_print_diagnostics.rs" -name = "hax-pretty-print-diagnostics" - [dependencies] serde.workspace = true serde_json.workspace = true @@ -29,9 +25,9 @@ schemars.workspace = true itertools.workspace = true clap.workspace = true paste = "1.0.11" -hax-cli-options.workspace = true +hax-frontend-exporter.workspace = true hax-frontend-exporter-options.workspace = true -hax-diagnostics.workspace = true +hax-types.workspace = true path-clean = "1.0.1" tempfile = "3.8" which.workspace = true @@ -39,15 +35,21 @@ version_check = "0.9" rustup-toolchain = "0.1" colored.workspace = true is-terminal = "0.4.9" +hax-phase-debug-webapp.workspace = true +inquire = "0.6" +annotate-snippets.workspace = true +serde-jsonlines = "0.5.0" +prettyplease = "0.2.20" +syn = { version = "2.*", features = ["full"] } +cargo_metadata.workspace = true +extension-traits = "1.0.1" [build-dependencies] serde.workspace = true serde_json.workspace = true +hax-types.workspace = true schemars.workspace = true hax-frontend-exporter.workspace = true -hax-diagnostics.workspace = true -hax-cli-options.workspace = true -hax-cli-options-engine.workspace = true hax-lib-macros-types = {workspace = true, features = ["schemars"]} version_check = "0.9" toml = "0.8" diff --git a/cli/subcommands/build.rs b/cli/subcommands/build.rs index dfb5503eb..224b4037c 100644 --- a/cli/subcommands/build.rs +++ b/cli/subcommands/build.rs @@ -16,11 +16,13 @@ fn rustc_version_env_var() { fn json_schema_static_asset() { let schema = schemars::schema_for!(( hax_frontend_exporter::Item, - hax_cli_options::Options, - hax_diagnostics::Diagnostics, - hax_cli_options_engine::EngineOptions, - hax_cli_options_engine::Output, - hax_cli_options_engine::WithDefIds, + hax_types::cli_options::Options, + hax_types::diagnostics::Diagnostics, + hax_types::engine_api::EngineOptions, + hax_types::engine_api::Output, + hax_types::engine_api::WithDefIds, + hax_types::engine_api::protocol::FromEngine, + hax_types::engine_api::protocol::ToEngine, hax_lib_macros_types::AttrPayload, )); serde_json::to_writer( diff --git a/cli/subcommands/src/cargo_hax.rs b/cli/subcommands/src/cargo_hax.rs index 9fd4eff12..ffcabb968 100644 --- a/cli/subcommands/src/cargo_hax.rs +++ b/cli/subcommands/src/cargo_hax.rs @@ -1,8 +1,16 @@ +use annotate_snippets::{Level, Renderer}; use clap::Parser; use colored::Colorize; -use hax_cli_options::NormalizePaths; -use hax_cli_options::Options; -use std::process::Command; +use hax_types::cli_options::*; +use hax_types::driver_api::*; +use hax_types::engine_api::*; +use is_terminal::IsTerminal; +use serde_jsonlines::BufReadExt; +use std::fs; +use std::io::BufRead; +use std::io::Write; +use std::path::PathBuf; +use std::process; /// Return a toolchain argument to pass to `cargo`: when the correct nightly is /// already present, this is None, otherwise we (1) ensure `rustup` is available @@ -49,7 +57,6 @@ pub fn get_args(subcommand: &str) -> Vec { const RUST_LOG_STYLE: &str = "RUST_LOG_STYLE"; fn rust_log_style() -> String { std::env::var(RUST_LOG_STYLE).unwrap_or_else(|_| { - use is_terminal::IsTerminal; if std::io::stderr().is_terminal() { "always".to_string() } else { @@ -66,25 +73,445 @@ fn rustflags() -> String { [rustflags, "--cfg hax".into()].join(" ") } +const ENGINE_BINARY_NAME: &str = "hax-engine"; +const ENGINE_BINARY_NOT_FOUND: &str = "The binary [hax-engine] was not found in your [PATH]."; + +/// Dynamically looks for binary [ENGINE_BINARY_NAME]. First, we +/// check whether [HAX_ENGINE_BINARY] is set, and use that if it +/// is. Then, we try to find [ENGINE_BINARY_NAME] in PATH. If not +/// found, detect whether nodejs is available, download the JS-compiled +/// engine and use it. +#[allow(unused_variables, unreachable_code)] +fn find_hax_engine(message_format: MessageFormat) -> process::Command { + use which::which; + + std::env::var("HAX_ENGINE_BINARY") + .ok() + .map(|name| process::Command::new(name)) + .or_else(|| { + which(ENGINE_BINARY_NAME) + .ok() + .map(|name| process::Command::new(name)) + }) + .or_else(|| { + which("node").ok().and_then(|_| { + if let Ok(true) = inquire::Confirm::new(&format!( + "{} Should I try to download it from GitHub?", + ENGINE_BINARY_NOT_FOUND, + )) + .with_default(true) + .prompt() + { + let cmd = process::Command::new("node"); + let engine_js_path: String = + panic!("TODO: Downloading from GitHub is not supported yet."); + cmd.arg(engine_js_path); + Some(cmd) + } else { + None + } + }) + }) + .unwrap_or_else(|| { + fn is_opam_setup_correctly() -> bool { + std::env::var("OPAM_SWITCH_PREFIX").is_ok() + } + HaxMessage::EngineNotFound { + is_opam_setup_correctly: is_opam_setup_correctly(), + } + .report(message_format, None); + std::process::exit(2); + }) +} + +use hax_types::diagnostics::message::HaxMessage; +use hax_types::diagnostics::report::ReportCtx; + +#[extension_traits::extension(trait ExtHaxMessage)] +impl HaxMessage { + fn report(self, message_format: MessageFormat, rctx: Option<&mut ReportCtx>) { + match message_format { + MessageFormat::Json => println!("{}", serde_json::to_string(&self).unwrap()), + MessageFormat::Human => self.report_styled(rctx), + } + } + fn report_styled(self, rctx: Option<&mut ReportCtx>) { + let renderer = Renderer::styled(); + match self { + Self::Diagnostic { + diagnostic, + working_dir, + } => { + let mut _rctx = None; + let rctx = rctx.unwrap_or_else(|| _rctx.get_or_insert(ReportCtx::default())); + diagnostic.with_message(rctx, &working_dir, Level::Error, |msg| { + eprintln!("{}", renderer.render(msg)) + }); + } + Self::EngineNotFound { + is_opam_setup_correctly, + } => { + use colored::Colorize; + let message = format!("hax: {}\n{}\n\n{} {}\n", + &ENGINE_BINARY_NOT_FOUND, + "Please make sure the engine is installed and is in PATH!", + "Hint: With OPAM, `eval $(opam env)` is necessary for OPAM binaries to be in PATH: make sure to run `eval $(opam env)` before running `cargo hax`.".bright_black(), + format!("(diagnostics: {})", if is_opam_setup_correctly { "opam seems okay ✓" } else {"opam seems not okay ❌"}).bright_black() + ); + let message = Level::Error.title(&message); + eprintln!("{}", renderer.render(message)) + } + Self::ProducedFile { mut path, wrote } => { + // Make path relative if possible + if let Ok(current_dir) = std::env::current_dir() { + if let Ok(relative) = path.strip_prefix(current_dir) { + path = PathBuf::from(".").join(relative).to_path_buf(); + } + } + let title = if wrote { + format!("hax: wrote file {}", path.display()) + } else { + format!("hax: unchanged file {}", path.display()) + }; + eprintln!("{}", renderer.render(Level::Info.title(&title))) + } + Self::HaxEngineFailure { exit_code } => { + let title = format!( + "hax: {} exited with non-zero code {}", + ENGINE_BINARY_NAME, exit_code, + ); + eprintln!("{}", renderer.render(Level::Error.title(&title))); + } + Self::CargoBuildFailure => { + let title = + format!("hax: running `cargo build` was not successful, continuing anyway."); + eprintln!("{}", renderer.render(Level::Warning.title(&title))); + } + Self::WarnExperimentalBackend { backend } => { + let title = format!( + "hax: Experimental backend \"{}\" is work in progress.", + backend + ); + eprintln!("{}", renderer.render(Level::Warning.title(&title))); + } + } + } +} + +/// Runs `hax-engine` +fn run_engine( + haxmeta: HaxMeta, + working_dir: PathBuf, + manifest_dir: PathBuf, + backend: &BackendOptions, + message_format: MessageFormat, +) -> bool { + let engine_options = EngineOptions { + backend: backend.clone(), + input: haxmeta.items, + impl_infos: haxmeta.impl_infos, + }; + let mut engine_subprocess = find_hax_engine(message_format) + .stdin(std::process::Stdio::piped()) + .stdout(std::process::Stdio::piped()) + .spawn() + .map_err(|e| { + if let std::io::ErrorKind::NotFound = e.kind() { + panic!( + "The binary [{}] was not found in your [PATH].", + ENGINE_BINARY_NAME + ) + } + e + }) + .unwrap(); + + let mut error = false; + let mut output = Output { + diagnostics: vec![], + files: vec![], + debug_json: None, + }; + { + let mut rctx = hax_types::diagnostics::report::ReportCtx::default(); + let mut stdin = std::io::BufWriter::new( + engine_subprocess + .stdin + .as_mut() + .expect("Could not write on stdin"), + ); + + macro_rules! send { + ($value:expr) => { + serde_json::to_writer(&mut stdin, $value).unwrap(); + stdin.write_all(b"\n").unwrap(); + stdin.flush().unwrap(); + }; + } + + send!(&engine_options); + + let out_dir = backend.output_dir.clone().unwrap_or({ + let relative_path: PathBuf = [ + "proofs", + format!("{}", backend.backend).as_str(), + "extraction", + ] + .iter() + .collect(); + manifest_dir.join(&relative_path) + }); + + let stdout = std::io::BufReader::new(engine_subprocess.stdout.take().unwrap()); + for msg in stdout.json_lines() { + let msg = msg.expect( + "Hax engine sent an invalid json value. \ + This might be caused by debug messages on stdout, \ + which is reserved for JSON communication with cargo-hax", + ); + use protocol::*; + match msg { + FromEngine::Exit => break, + FromEngine::Diagnostic(diagnostic) => { + error = true; + if backend.dry_run { + output.diagnostics.push(diagnostic.clone()) + } + HaxMessage::Diagnostic { + diagnostic, + working_dir: working_dir.clone(), + } + .report(message_format, Some(&mut rctx)); + } + FromEngine::File(file) => { + if backend.dry_run { + output.files.push(file) + } else { + let path = out_dir.join(&file.path); + std::fs::create_dir_all(&path.parent().unwrap()).unwrap(); + let mut wrote = false; + if fs::read_to_string(&path).as_ref().ok() != Some(&file.contents) { + std::fs::write(&path, file.contents).unwrap(); + wrote = true; + } + HaxMessage::ProducedFile { path, wrote }.report(message_format, None) + } + } + FromEngine::DebugString(debug) => { + output.debug_json = Some(debug); + } + FromEngine::PrettyPrintDiagnostic(diag) => { + send!(&ToEngine::PrettyPrintedDiagnostic(format!("{}", diag))); + } + FromEngine::PrettyPrintRust(code) => { + let code = match syn::parse_file(&code) { + Ok(file) => match std::panic::catch_unwind(|| prettyplease::unparse(&file)) + { + Ok(pp) => Ok(pp), + Err(err) => Err(format!("prettyplease panicked with: {:#?}", err)), + }, + Err(err) => Err(format!("{}", err)), + }; + send!(&ToEngine::PrettyPrintedRust(code)); + } + FromEngine::Ping => { + send!(&ToEngine::Pong); + } + } + } + drop(stdin); + } + + let exit_status = engine_subprocess.wait().unwrap(); + if !exit_status.success() { + HaxMessage::HaxEngineFailure { + exit_code: exit_status.code().unwrap_or(-1), + }; + std::process::exit(1); + } + + if backend.dry_run { + serde_json::to_writer(std::io::BufWriter::new(std::io::stdout()), &output).unwrap() + } + if let Some(debug_json) = &output.debug_json { + use DebugEngineMode; + match &backend.debug_engine { + Some(DebugEngineMode::Interactive) => { + eprintln!("----------------------------------------------"); + eprintln!("----------------------------------------------"); + eprintln!("----------------------------------------------"); + eprintln!("-- Engine debug mode. Press CTRL+C to exit. --"); + eprintln!("----------------------------------------------"); + eprintln!("----------------------------------------------"); + eprintln!("----------------------------------------------"); + hax_phase_debug_webapp::run(|| debug_json.clone()) + } + Some(DebugEngineMode::File(_file)) if !backend.dry_run => { + println!("{}", debug_json) + } + _ => (), + } + } + + error +} + +/// Uses `cargo metadata` to compute a derived target directory. +fn target_dir(suffix: &str) -> PathBuf { + let metadata = cargo_metadata::MetadataCommand::new().exec().unwrap(); + let mut dir = metadata.target_directory; + dir.push(suffix); + dir.into() +} + +/// Calls `cargo` with a custom driver which computes `haxmeta` files +/// in `TARGET`. One `haxmeta` file is produced by crate. Each +/// `haxmeta` file contains the full AST of one crate. +fn compute_haxmeta_files(options: &Options) -> (Vec, i32) { + let mut cmd = { + let mut cmd = process::Command::new("cargo"); + if let Some(toolchain) = toolchain() { + cmd.env("RUSTUP_TOOLCHAIN", toolchain); + } + cmd.args(["build".into()].iter().chain(options.cargo_flags.iter())); + const COLOR_FLAG: &str = "--color"; + let explicit_color_flag = options.cargo_flags.iter().any(|flag| flag == COLOR_FLAG); + if !explicit_color_flag && std::io::stderr().is_terminal() { + cmd.args([COLOR_FLAG, "always"]); + } + const MSG_FMT_FLAG: &str = "--message-format"; + let explicit_msg_fmt_flag = options.cargo_flags.iter().any(|flag| flag == MSG_FMT_FLAG); + if !explicit_msg_fmt_flag && options.message_format == MessageFormat::Json { + cmd.args([MSG_FMT_FLAG, "json"]); + } + cmd.stderr(std::process::Stdio::piped()); + if !options.no_custom_target_directory { + cmd.env("CARGO_TARGET_DIR", target_dir("hax")); + }; + cmd.env( + "RUSTC_WORKSPACE_WRAPPER", + std::env::var("HAX_RUSTC_DRIVER_BINARY") + .unwrap_or("driver-hax-frontend-exporter".into()), + ) + .env(RUST_LOG_STYLE, rust_log_style()) + .env(RUSTFLAGS, rustflags()) + .env( + ENV_VAR_OPTIONS_FRONTEND, + serde_json::to_string(&options) + .expect("Options could not be converted to a JSON string"), + ); + cmd + }; + + let mut child = cmd.spawn().unwrap(); + let haxmeta_files = { + let mut haxmeta_files = vec![]; + let stderr = child.stderr.take().unwrap(); + let stderr = std::io::BufReader::new(stderr); + for line in std::io::BufReader::new(stderr).lines() { + if let Ok(line) = line { + if let Some(msg) = line.strip_prefix(HAX_DRIVER_STDERR_PREFIX) { + use HaxDriverMessage; + let msg = serde_json::from_str(msg).unwrap(); + match msg { + HaxDriverMessage::EmitHaxMeta(data) => haxmeta_files.push(data), + } + } else { + eprintln!("{}", line); + } + } + } + haxmeta_files + }; + + let status = child + .wait() + .expect("`driver-hax-frontend-exporter`: could not start?"); + + let exit_code = if !status.success() { + HaxMessage::CargoBuildFailure.report(options.message_format, None); + status.code().unwrap_or(254) + } else { + 0 + }; + (haxmeta_files, exit_code) +} + +/// Run the command given by the user +fn run_command(options: &Options, haxmeta_files: Vec) -> bool { + match options.command.clone() { + Command::JSON { + output_file, + kind, + include_extra, + .. + } => { + with_kind_type!(kind, || { + for EmitHaxMetaMessage { path, .. } in haxmeta_files { + let haxmeta: HaxMeta = HaxMeta::read(fs::File::open(&path).unwrap()); + let dest = output_file.open_or_stdout(); + (if include_extra { + serde_json::to_writer( + dest, + &WithDefIds { + def_ids: haxmeta.def_ids, + impl_infos: haxmeta.impl_infos, + items: haxmeta.items, + }, + ) + } else { + serde_json::to_writer(dest, &haxmeta.items) + }) + .unwrap() + } + }); + false + } + Command::Backend(backend) => { + use hax_frontend_exporter::ThirBody as Body; + use Backend; + + if matches!(backend.backend, Backend::Easycrypt | Backend::ProVerif(..)) { + HaxMessage::WarnExperimentalBackend { + backend: backend.backend.clone(), + } + .report(options.message_format, None); + } + + let mut error = false; + for EmitHaxMetaMessage { + working_dir, + manifest_dir, + path, + } in haxmeta_files + { + let haxmeta: HaxMeta = HaxMeta::read(fs::File::open(&path).unwrap()); + + error = error + || run_engine( + haxmeta, + working_dir, + manifest_dir, + &backend, + options.message_format, + ); + } + error + } + } +} + fn main() { let args: Vec = get_args("hax"); let mut options = Options::parse_from(args.iter()); options.normalize_paths(); - let mut cmd = Command::new("cargo"); - if let Some(toolchain) = toolchain() { - cmd.env("RUSTUP_TOOLCHAIN", toolchain); - } - cmd.args(["build".into()].iter().chain(options.cargo_flags.iter())); - cmd.env( - "RUSTC_WORKSPACE_WRAPPER", - std::env::var("HAX_RUSTC_DRIVER_BINARY").unwrap_or("driver-hax-frontend-exporter".into()), - ) - .env(RUST_LOG_STYLE, rust_log_style()) - .env(RUSTFLAGS, rustflags()) - .env( - hax_cli_options::ENV_VAR_OPTIONS_FRONTEND, - serde_json::to_string(&options).expect("Options could not be converted to a JSON string"), - ); - std::process::exit(cmd.spawn().unwrap().wait().unwrap().code().unwrap_or(254)) + let (haxmeta_files, exit_code) = compute_haxmeta_files(&options); + let error = run_command(&options, haxmeta_files); + + std::process::exit(if exit_code == 0 && error { + 1 + } else { + exit_code + }) } diff --git a/cli/subcommands/src/pretty_print_diagnostics.rs b/cli/subcommands/src/pretty_print_diagnostics.rs deleted file mode 100644 index 22c7c46a2..000000000 --- a/cli/subcommands/src/pretty_print_diagnostics.rs +++ /dev/null @@ -1,16 +0,0 @@ -//! This binary is useful for the engine: from OCaml we need to pretty -//! print Hax-errors so that we can inline those as failed items or -//! failed expressions in the generated modules. - -//! Thus, this binary expects a JSON diagnostics error on its stdin -//! and outputs on stdout its pretty, `Display`ed version. - -#![feature(rustc_private)] -extern crate rustc_driver; - -use hax_diagnostics::Diagnostics as D; -use serde_json::{from_reader, Value}; - -fn main() { - println!("{}", from_reader::<_, D>(std::io::stdin()).unwrap()) -} diff --git a/dependabot.yml b/dependabot.yml new file mode 100644 index 000000000..304f54aa1 --- /dev/null +++ b/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: +- package-ecosystem: "cargo" + directory: "/" + schedule: + interval: "weekly" diff --git a/engine/DEV.md b/engine/DEV.md index 5a5d28d5f..a0d2ef381 100644 --- a/engine/DEV.md +++ b/engine/DEV.md @@ -42,6 +42,12 @@ To show the file nicely formated, use: `dune describe pp lib/types.ml` (or `dune You can also use `dune utop` and then `#show_type Hax_engine.Types.SOME_TYPE` and `#show_constructor Hax_engine.Types.SOME_CONSTRUCTOR`. +### Visitors +The module `Ast_visitors` provides a `Make` functor that takes a feature set and outputs a module that defines the `map`, `mapreduce` and `reduce` classes. + +Those visitors are generated by `./utils/generate_visitors`. +To see the implementation of the `Ast_visitors` module, run `dune describe pp lib/ast_visitors.ml`. + ## Debugging the phases You can enable a debug mode that prints a Rustish AST at each phase, that you can browse interactively along with the actual AST. diff --git a/engine/backends/coq/coq/coq_backend.ml b/engine/backends/coq/coq/coq_backend.ml index 41058c99c..a4564bb5a 100644 --- a/engine/backends/coq/coq/coq_backend.ml +++ b/engine/backends/coq/coq/coq_backend.ml @@ -40,7 +40,10 @@ module SubtypeToInputLanguage and type while_loop = Features.Off.while_loop and type for_index_loop = Features.Off.for_index_loop and type quote = Features.Off.quote - and type state_passing_loop = Features.Off.state_passing_loop) = + and type state_passing_loop = Features.Off.state_passing_loop + and type dyn = Features.Off.dyn + and type match_guard = Features.Off.match_guard + and type trait_item_default = Features.Off.trait_item_default) = struct module FB = InputLanguage @@ -573,6 +576,7 @@ struct ( U.Concrete_ident_view.to_definition_name x.ti_ident, match x.ti_v with | TIFn fn_ty -> pty span fn_ty + | TIDefault _ -> . | _ -> __TODO_ty__ span "field_ty" )) items ); ] @@ -699,10 +703,12 @@ module TransformToInputLanguage = [%functor_application Phases.Reject.RawOrMutPointer(Features.Rust) |> Phases.And_mut_defsite + |> Phases.Reconstruct_asserts |> Phases.Reconstruct_for_loops |> Phases.Direct_and_mut |> Phases.Reject.Arbitrary_lhs |> Phases.Drop_blocks + |> Phases.Drop_match_guards |> Phases.Reject.Continue |> Phases.Drop_references |> Phases.Trivialize_assign_lhs @@ -714,6 +720,8 @@ module TransformToInputLanguage = |> Phases.Reject.EarlyExit |> Phases.Functionalize_loops |> Phases.Reject.As_pattern + |> Phases.Reject.Dyn + |> Phases.Reject.Trait_item_default |> SubtypeToInputLanguage |> Identity ] diff --git a/engine/backends/coq/ssprove/ssprove_backend.ml b/engine/backends/coq/ssprove/ssprove_backend.ml index 260ea21e9..7d8207385 100644 --- a/engine/backends/coq/ssprove/ssprove_backend.ml +++ b/engine/backends/coq/ssprove/ssprove_backend.ml @@ -40,7 +40,10 @@ module SubtypeToInputLanguage and type arbitrary_lhs = Features.Off.arbitrary_lhs and type nontrivial_lhs = Features.Off.nontrivial_lhs and type quote = Features.Off.quote - and type block = Features.Off.block) = + and type block = Features.Off.block + and type dyn = Features.Off.dyn + and type match_guard = Features.Off.match_guard + and type trait_item_default = Features.Off.trait_item_default) = struct module FB = InputLanguage @@ -564,10 +567,12 @@ module TransformToInputLanguage (* : PHASE *) = [%functor_application Phases.Reject.RawOrMutPointer(Features.Rust) |> Phases.And_mut_defsite + |> Phases.Reconstruct_asserts |> Phases.Reconstruct_for_loops |> Phases.Direct_and_mut |> Phases.Reject.Arbitrary_lhs |> Phases.Drop_blocks + |> Phases.Drop_match_guards (* |> Phases.Reject.Continue *) |> Phases.Drop_references |> Phases.Trivialize_assign_lhs @@ -580,6 +585,8 @@ module TransformToInputLanguage (* : PHASE *) = |> Phases.Reject.EarlyExit (* |> Phases.Functionalize_loops *) |> Phases.Reject.As_pattern + |> Phases.Reject.Dyn + |> Phases.Reject.Trait_item_default |> SubtypeToInputLanguage |> Identity ] @@ -1337,6 +1344,10 @@ struct | _ -> .) args ) ); ] + | GCProjection _ -> + Error.unimplemented ~issue_id:549 + ~details:"Projections of an associated type is not yet supported." + span | _ -> . let pgeneric (span : Ast.span) (generics : AST.generics) : @@ -1753,7 +1764,8 @@ struct SSP.AST.NameTy (pconcrete_ident x.ti_ident); ] ) )) - impl_idents) + impl_idents + | _ -> .) items ); ] @ List.concat_map @@ -1764,6 +1776,7 @@ struct SSP.AST.HintUnfold (pconcrete_ident x.ti_ident ^ "_loc", None); ] + | TIDefault _ -> . | _ -> []) items | Impl { generics; self_ty; of_trait = name, gen_vals; items } -> diff --git a/engine/backends/easycrypt/easycrypt_backend.ml b/engine/backends/easycrypt/easycrypt_backend.ml index 115ebda06..fd5bbc02f 100644 --- a/engine/backends/easycrypt/easycrypt_backend.ml +++ b/engine/backends/easycrypt/easycrypt_backend.ml @@ -58,6 +58,9 @@ module RejectNotEC (FA : Features.T) = struct let for_loop = reject let while_loop = reject let quote = reject + let dyn = reject + let match_guard = reject + let trait_item_default = reject let construct_base _ _ = Features.On.construct_base let for_index_loop _ _ = Features.On.for_index_loop @@ -345,8 +348,9 @@ open Phase_utils module TransformToInputLanguage = [%functor_application Phases.Reject.RawOrMutPointer Features.Rust |> Phases.And_mut_defsite -|> Phases.Reconstruct_for_loops |> Phases.Direct_and_mut |> Phases.Drop_blocks -|> Phases.Reject.Continue |> Phases.Drop_references |> RejectNotEC] +|> Phases.Reconstruct_asserts |> Phases.Reconstruct_for_loops +|> Phases.Direct_and_mut |> Phases.Drop_blocks |> Phases.Reject.Continue +|> Phases.Drop_references |> RejectNotEC] let apply_phases (_bo : BackendOptions.t) (items : Ast.Rust.item list) : AST.item list = diff --git a/engine/backends/fstar/fstar-surface-ast/FStar_BaseTypes.ml b/engine/backends/fstar/fstar-surface-ast/FStar_BaseTypes.ml index 66b018bd1..cb3dbc318 100644 --- a/engine/backends/fstar/fstar-surface-ast/FStar_BaseTypes.ml +++ b/engine/backends/fstar/fstar-surface-ast/FStar_BaseTypes.ml @@ -1,10 +1,10 @@ type char = FStar_Char.char[@@deriving yojson,show] -type float = FStar_Float.float[@@deriving yojson,show] -type double = FStar_Float.double[@@deriving yojson,show] -type byte = FStar_UInt8.byte[@@deriving yojson,show] -type int8 = FStar_Int8.int8 -type uint8 = FStar_UInt8.uint8 -type int16 = FStar_Int16.int16 -type uint16 = FStar_UInt16.uint16 -type int32 = FStar_Int32.int32 -type int64 = FStar_Int64.int64 +type float = Base.Float.t +type double = Base.Float.t +type byte = Base.Int.t +type int8 = Stdint.Int8.t +type uint8 = Stdint.Uint8.t +type int16 = Stdint.Int16.t +type uint16 = Stdint.Uint16.t +type int32 = Stdint.Int32.t +type int64 = Stdint.Int64.t diff --git a/engine/backends/fstar/fstar-surface-ast/FStar_BigInt.ml b/engine/backends/fstar/fstar-surface-ast/FStar_BigInt.ml deleted file mode 100644 index 2314ae4ff..000000000 --- a/engine/backends/fstar/fstar-surface-ast/FStar_BigInt.ml +++ /dev/null @@ -1,44 +0,0 @@ -type bigint = Z.t -type t = bigint - -let zero = Z.zero -let one = Z.one -let two = Z.of_string "2" - -let succ_big_int = Z.succ -let pred_big_int = Z.pred -let minus_big_int = Z.neg -let abs_big_int = Z.abs - -let add_big_int = Z.add -let mult_big_int = Z.mul -let sub_big_int = Z.sub -let div_big_int = Z.ediv -let mod_big_int = Z.erem - -let eq_big_int = Z.equal -let le_big_int = Z.leq -let lt_big_int = Z.lt -let ge_big_int = Z.geq -let gt_big_int = Z.gt - -let logand_big_int = Z.logand -let logor_big_int = Z.logor -let logxor_big_int = Z.logxor -let lognot_big_int = Z.lognot - -let shift_left_big_int x y = Z.shift_left x (Z.to_int y) -let shift_right_big_int x y = Z.shift_right x (Z.to_int y) - -let sqrt_big_int = Z.sqrt - -let string_of_big_int = Z.to_string -let big_int_of_string = Z.of_string - -let of_int = Z.of_int -let to_int = Z.to_int - -let of_int_fs x = x -let to_int_fs x = x - -let of_hex x = Z.of_string ("0x" ^ x) diff --git a/engine/backends/fstar/fstar-surface-ast/FStar_Char.ml b/engine/backends/fstar/fstar-surface-ast/FStar_Char.ml index 2727e7236..4f17aaa6b 100644 --- a/engine/backends/fstar/fstar-surface-ast/FStar_Char.ml +++ b/engine/backends/fstar/fstar-surface-ast/FStar_Char.ml @@ -1,21 +1,2 @@ module UChar = BatUChar - -module U32 = FStar_UInt32 - type char = int[@@deriving yojson,show] -type char_code = U32.t - -(* FIXME(adl) UChar.lowercase/uppercase removed from recent Batteries. Use Camomile? *) -let lowercase (x:char) : char = - try Char.code (Char.lowercase_ascii (Char.chr x)) - with _ -> x - -let uppercase (x:char) : char = - try Char.code (Char.uppercase_ascii (Char.chr x)) - with _ -> x - -let int_of_char (x:char) : Z.t= Z.of_int x -let char_of_int (i:Z.t) : char = Z.to_int i - -let u32_of_char (x:char) : char_code = U32.of_native_int x -let char_of_u32 (x:char_code) : char = U32.to_native_int x diff --git a/engine/backends/fstar/fstar-surface-ast/FStar_Common.ml b/engine/backends/fstar/fstar-surface-ast/FStar_Common.ml deleted file mode 100644 index 373232355..000000000 --- a/engine/backends/fstar/fstar-surface-ast/FStar_Common.ml +++ /dev/null @@ -1,177 +0,0 @@ -open Prims -let (has_cygpath : Prims.bool) = - try - (fun uu___ -> - match () with - | () -> - let t_out = - FStar_Compiler_Util.run_process "has_cygpath" "which" - ["cygpath"] FStar_Pervasives_Native.None in - (FStar_Compiler_Util.trim_string t_out) = "/usr/bin/cygpath") () - with | uu___ -> false -let (try_convert_file_name_to_mixed : Prims.string -> Prims.string) = - let cache = FStar_Compiler_Util.smap_create (Prims.of_int (20)) in - fun s -> - if has_cygpath && (FStar_Compiler_Util.starts_with s "/") - then - let uu___ = FStar_Compiler_Util.smap_try_find cache s in - match uu___ with - | FStar_Pervasives_Native.Some s1 -> s1 - | FStar_Pervasives_Native.None -> - let label = "try_convert_file_name_to_mixed" in - let out = - let uu___1 = - FStar_Compiler_Util.run_process label "cygpath" ["-m"; s] - FStar_Pervasives_Native.None in - FStar_Compiler_Effect.op_Bar_Greater uu___1 - FStar_Compiler_Util.trim_string in - (FStar_Compiler_Util.smap_add cache s out; out) - else s -let snapshot : - 'a 'b 'c . - ('a -> 'b) -> - 'c Prims.list FStar_Compiler_Effect.ref -> 'a -> (Prims.int * 'b) - = - fun push -> - fun stackref -> - fun arg -> - FStar_Compiler_Util.atomically - (fun uu___ -> - let len = - let uu___1 = FStar_Compiler_Effect.op_Bang stackref in - FStar_Compiler_List.length uu___1 in - let arg' = push arg in (len, arg')) -let rollback : - 'a 'c . - (unit -> 'a) -> - 'c Prims.list FStar_Compiler_Effect.ref -> - Prims.int FStar_Pervasives_Native.option -> 'a - = - fun pop -> - fun stackref -> - fun depth -> - let rec aux n = - if n <= Prims.int_zero - then failwith "Too many pops" - else - if n = Prims.int_one - then pop () - else ((let uu___3 = pop () in ()); aux (n - Prims.int_one)) in - let curdepth = - let uu___ = FStar_Compiler_Effect.op_Bang stackref in - FStar_Compiler_List.length uu___ in - let n = - match depth with - | FStar_Pervasives_Native.Some d -> curdepth - d - | FStar_Pervasives_Native.None -> Prims.int_one in - FStar_Compiler_Util.atomically (fun uu___ -> aux n) -let raise_failed_assertion : 'uuuuu . Prims.string -> 'uuuuu = - fun msg -> - let uu___ = FStar_Compiler_Util.format1 "Assertion failed: %s" msg in - failwith uu___ -let (runtime_assert : Prims.bool -> Prims.string -> unit) = - fun b -> - fun msg -> if Prims.op_Negation b then raise_failed_assertion msg else () -let __string_of_list : - 'a . Prims.string -> ('a -> Prims.string) -> 'a Prims.list -> Prims.string - = - fun delim -> - fun f -> - fun l -> - match l with - | [] -> "[]" - | x::xs -> - let strb = FStar_Compiler_Util.new_string_builder () in - (FStar_Compiler_Util.string_builder_append strb "["; - (let uu___2 = f x in - FStar_Compiler_Util.string_builder_append strb uu___2); - FStar_Compiler_List.iter - (fun x1 -> - FStar_Compiler_Util.string_builder_append strb delim; - (let uu___4 = f x1 in - FStar_Compiler_Util.string_builder_append strb uu___4)) xs; - FStar_Compiler_Util.string_builder_append strb "]"; - FStar_Compiler_Util.string_of_string_builder strb) -let string_of_list : - 'uuuuu . - unit -> ('uuuuu -> Prims.string) -> 'uuuuu Prims.list -> Prims.string - = fun uu___ -> __string_of_list ", " -let string_of_list' : - 'uuuuu . - unit -> ('uuuuu -> Prims.string) -> 'uuuuu Prims.list -> Prims.string - = fun uu___ -> __string_of_list "; " -let string_of_set : - 'a . ('a -> Prims.string) -> 'a FStar_Compiler_Util.set -> Prims.string = - fun f -> - fun l -> - let uu___ = FStar_Compiler_Util.set_elements l in - match uu___ with - | [] -> "{}" - | x::xs -> - let strb = FStar_Compiler_Util.new_string_builder () in - (FStar_Compiler_Util.string_builder_append strb "{"; - (let uu___3 = f x in - FStar_Compiler_Util.string_builder_append strb uu___3); - FStar_Compiler_List.iter - (fun x1 -> - FStar_Compiler_Util.string_builder_append strb ", "; - (let uu___5 = f x1 in - FStar_Compiler_Util.string_builder_append strb uu___5)) xs; - FStar_Compiler_Util.string_builder_append strb "}"; - FStar_Compiler_Util.string_of_string_builder strb) -let list_of_option : 'a . 'a FStar_Pervasives_Native.option -> 'a Prims.list - = - fun o -> - match o with - | FStar_Pervasives_Native.None -> [] - | FStar_Pervasives_Native.Some x -> [x] -let string_of_option : - 'uuuuu . - ('uuuuu -> Prims.string) -> - 'uuuuu FStar_Pervasives_Native.option -> Prims.string - = - fun f -> - fun uu___ -> - match uu___ with - | FStar_Pervasives_Native.None -> "None" - | FStar_Pervasives_Native.Some x -> - let uu___1 = f x in Prims.op_Hat "Some " uu___1 -let tabulate : 'a . Prims.int -> (Prims.int -> 'a) -> 'a Prims.list = - fun n -> - fun f -> - let rec aux i = - if i < n - then - let uu___ = f i in - let uu___1 = aux (i + Prims.int_one) in uu___ :: uu___1 - else [] in - aux Prims.int_zero -let rec max_prefix : - 'a . ('a -> Prims.bool) -> 'a Prims.list -> ('a Prims.list * 'a Prims.list) - = - fun f -> - fun xs -> - match xs with - | [] -> ([], []) - | x::xs1 when f x -> - let uu___ = max_prefix f xs1 in - (match uu___ with | (l, r) -> ((x :: l), r)) - | x::xs1 -> ([], (x :: xs1)) -let max_suffix : - 'a . ('a -> Prims.bool) -> 'a Prims.list -> ('a Prims.list * 'a Prims.list) - = - fun f -> - fun xs -> - let rec aux acc xs1 = - match xs1 with - | [] -> (acc, []) - | x::xs2 when f x -> aux (x :: acc) xs2 - | x::xs2 -> (acc, (x :: xs2)) in - let uu___ = - let uu___1 = - FStar_Compiler_Effect.op_Bar_Greater xs FStar_Compiler_List.rev in - FStar_Compiler_Effect.op_Bar_Greater uu___1 (aux []) in - FStar_Compiler_Effect.op_Bar_Greater uu___ - (fun uu___1 -> - match uu___1 with - | (xs1, ys) -> ((FStar_Compiler_List.rev ys), xs1)) \ No newline at end of file diff --git a/engine/backends/fstar/fstar-surface-ast/FStar_CommonST.ml b/engine/backends/fstar/fstar-surface-ast/FStar_CommonST.ml deleted file mode 100644 index 2a7984389..000000000 --- a/engine/backends/fstar/fstar-surface-ast/FStar_CommonST.ml +++ /dev/null @@ -1,19 +0,0 @@ -open FStar_Monotonic_Heap - -let read x = !x - -let op_Bang x = read x - -let write x y = x := y - -let op_Colon_Equals x y = write x y - -let alloc contents = ref contents - -let recall = (fun r -> ()) -let get () = () - -type 'a witnessed = | C - -let gst_witness = (fun r -> ()) -let gst_recall = (fun r -> ()) diff --git a/engine/backends/fstar/fstar-surface-ast/FStar_Compiler_Option.ml b/engine/backends/fstar/fstar-surface-ast/FStar_Compiler_Option.ml deleted file mode 100644 index aeb9eeabb..000000000 --- a/engine/backends/fstar/fstar-surface-ast/FStar_Compiler_Option.ml +++ /dev/null @@ -1,37 +0,0 @@ -open Prims -let isNone : 'a . 'a FStar_Pervasives_Native.option -> Prims.bool = - fun uu___ -> - match uu___ with - | FStar_Pervasives_Native.None -> true - | FStar_Pervasives_Native.Some uu___1 -> false -let isSome : 'a . 'a FStar_Pervasives_Native.option -> Prims.bool = - fun uu___ -> - match uu___ with - | FStar_Pervasives_Native.Some uu___1 -> true - | FStar_Pervasives_Native.None -> false -let map : - 'a 'b . - ('a -> 'b) -> - 'a FStar_Pervasives_Native.option -> 'b FStar_Pervasives_Native.option - = - fun f -> - fun uu___ -> - match uu___ with - | FStar_Pervasives_Native.Some x -> - let uu___1 = f x in FStar_Pervasives_Native.Some uu___1 - | FStar_Pervasives_Native.None -> FStar_Pervasives_Native.None -let mapTot : - 'a 'b . - ('a -> 'b) -> - 'a FStar_Pervasives_Native.option -> 'b FStar_Pervasives_Native.option - = - fun f -> - fun uu___ -> - match uu___ with - | FStar_Pervasives_Native.Some x -> FStar_Pervasives_Native.Some (f x) - | FStar_Pervasives_Native.None -> FStar_Pervasives_Native.None -let get : 'a . 'a FStar_Pervasives_Native.option -> 'a = - fun uu___ -> - match uu___ with - | FStar_Pervasives_Native.Some x -> x - | FStar_Pervasives_Native.None -> failwith "empty option" \ No newline at end of file diff --git a/engine/backends/fstar/fstar-surface-ast/FStar_Compiler_Range.ml b/engine/backends/fstar/fstar-surface-ast/FStar_Compiler_Range.ml index 9910cb409..fb7330196 100644 --- a/engine/backends/fstar/fstar-surface-ast/FStar_Compiler_Range.ml +++ b/engine/backends/fstar/fstar-surface-ast/FStar_Compiler_Range.ml @@ -101,22 +101,7 @@ let (string_of_pos : pos -> Prims.string) = FStar_Compiler_Util.format2 "%s,%s" uu___ uu___1 let (string_of_file_name : Prims.string -> Prims.string) = fun f -> - let uu___ = FStar_Options.ide () in - if uu___ - then - try - (fun uu___1 -> - match () with - | () -> - let uu___2 = - let uu___3 = FStar_Compiler_Util.basename f in - FStar_Options.find_file uu___3 in - (match uu___2 with - | FStar_Pervasives_Native.None -> f - | FStar_Pervasives_Native.Some absolute_path -> absolute_path)) - () - with | uu___1 -> f - else f + f let (file_of_range : range -> Prims.string) = fun r -> let f = (r.def_range).file_name in string_of_file_name f let (set_file_of_range : range -> Prims.string -> range) = @@ -181,69 +166,3 @@ let (extend_to_end_of_line : range -> range) = let uu___1 = start_of_range r in let uu___2 = let uu___3 = end_of_range r in end_of_line uu___3 in mk_range uu___ uu___1 uu___2 -let (prims_to_fstar_range : - ((Prims.string * (Prims.int * Prims.int) * (Prims.int * Prims.int)) * - (Prims.string * (Prims.int * Prims.int) * (Prims.int * Prims.int))) -> - range) - = - fun r -> - let uu___ = r in - match uu___ with - | (r1, r2) -> - let uu___1 = r1 in - (match uu___1 with - | (f1, s1, e1) -> - let uu___2 = r2 in - (match uu___2 with - | (f2, s2, e2) -> - let s11 = - mk_pos (FStar_Pervasives_Native.fst s1) - (FStar_Pervasives_Native.snd s1) in - let e11 = - mk_pos (FStar_Pervasives_Native.fst e1) - (FStar_Pervasives_Native.snd e1) in - let s21 = - mk_pos (FStar_Pervasives_Native.fst s2) - (FStar_Pervasives_Native.snd s2) in - let e21 = - mk_pos (FStar_Pervasives_Native.fst e2) - (FStar_Pervasives_Native.snd e2) in - let r11 = mk_rng f1 s11 e11 in - let r21 = mk_rng f2 s21 e21 in - { def_range = r11; use_range = r21 })) -let (json_of_pos : pos -> FStar_Compiler_Util.json) = - fun pos1 -> - let uu___ = - let uu___1 = - let uu___2 = line_of_pos pos1 in FStar_Compiler_Util.JsonInt uu___2 in - let uu___2 = - let uu___3 = - let uu___4 = col_of_pos pos1 in FStar_Compiler_Util.JsonInt uu___4 in - [uu___3] in - uu___1 :: uu___2 in - FStar_Compiler_Util.JsonList uu___ -let (json_of_range_fields : - Prims.string -> pos -> pos -> FStar_Compiler_Util.json) = - fun file -> - fun b -> - fun e -> - let uu___ = - let uu___1 = - let uu___2 = let uu___3 = json_of_pos b in ("beg", uu___3) in - let uu___3 = - let uu___4 = let uu___5 = json_of_pos e in ("end", uu___5) in - [uu___4] in - uu___2 :: uu___3 in - ("fname", (FStar_Compiler_Util.JsonStr file)) :: uu___1 in - FStar_Compiler_Util.JsonAssoc uu___ -let (json_of_use_range : range -> FStar_Compiler_Util.json) = - fun r -> - let uu___ = file_of_use_range r in - let uu___1 = start_of_use_range r in - let uu___2 = end_of_use_range r in - json_of_range_fields uu___ uu___1 uu___2 -let (json_of_def_range : range -> FStar_Compiler_Util.json) = - fun r -> - let uu___ = file_of_range r in - let uu___1 = start_of_range r in - let uu___2 = end_of_range r in json_of_range_fields uu___ uu___1 uu___2 \ No newline at end of file diff --git a/engine/backends/fstar/fstar-surface-ast/FStar_Compiler_Util.ml b/engine/backends/fstar/fstar-surface-ast/FStar_Compiler_Util.ml index 2294217ee..6da6ede86 100644 --- a/engine/backends/fstar/fstar-surface-ast/FStar_Compiler_Util.ml +++ b/engine/backends/fstar/fstar-surface-ast/FStar_Compiler_Util.ml @@ -1,3 +1,6 @@ +let ensure_decimal s = Z.to_string (Z.of_string s) + + let max_int = Z.of_int max_int let is_letter c = if c > 255 then false else BatChar.is_letter (BatChar.chr c) let is_digit c = if c > 255 then false else BatChar.is_digit (BatChar.chr c) @@ -12,18 +15,6 @@ let is_punctuation c = List.mem c [33; 34; 35; 37; 38; 39; 40; 41; 42; 44; 45; 4 let return_all x = x -type time = float -let now () = BatUnix.gettimeofday () -let now_ms () = Z.of_int (int_of_float (now () *. 1000.0)) -let time_diff (t1:time) (t2:time) : float * Prims.int = - let n = t2 -. t1 in - n, - Z.of_float (n *. 1000.0) -let record_time f = - let start = now () in - let res = f () in - let _, elapsed = time_diff start (now()) in - res, elapsed let get_file_last_modification_time f = (BatUnix.stat f).BatUnix.st_mtime let is_before t1 t2 = compare t1 t2 < 0 let string_of_time = string_of_float @@ -69,195 +60,6 @@ let with_sigint_handler handler f = (fun () -> set_sigint_handler handler; f ()) () -type proc = - {pid: int; - inc : in_channel; - outc : out_channel; - mutable killed : bool; - stop_marker: (string -> bool) option; - id : string; - start_time : time} - -let all_procs : (proc list) ref = ref [] - -let lock () = () -let release () = () -let sleep n = Thread.delay ((Z.to_float n) /. 1000.) - -let mlock = Mutex.create () - -let monitor_enter _ = Mutex.lock mlock -let monitor_exit _ = Mutex.unlock mlock -let monitor_wait _ = () -let monitor_pulse _ = () -let current_tid _ = Z.zero - -let atomically f = (* This function only protects against signals *) - let finalizer () = - decr sigint_delay; - if !sigint_pending && !sigint_delay = 0 then - raise_sigint () in - let body f = - incr sigint_delay; f () in - BatPervasives.finally finalizer body f - -let with_monitor _ f x = atomically (fun () -> - monitor_enter (); - BatPervasives.finally monitor_exit f x) - -let spawn f = - let _ = Thread.create f () in () - -let stack_dump () = Printexc.raw_backtrace_to_string (Printexc.get_callstack 1000) - -(* On the OCaml side it would make more sense to take stop_marker in - ask_process, but the F# side isn't built that way *) -let start_process' - (id: string) (prog: string) (args: string list) - (stop_marker: (string -> bool) option) : proc = - let (stdout_r, stdout_w) = Unix.pipe () in - let (stdin_r, stdin_w) = Unix.pipe () in - Unix.set_close_on_exec stdin_w; - Unix.set_close_on_exec stdout_r; - let pid = Unix.create_process prog (Array.of_list (prog :: args)) stdin_r stdout_w stdout_w in - Unix.close stdin_r; - Unix.close stdout_w; - let proc = { pid = pid; id = prog ^ ":" ^ id; - inc = Unix.in_channel_of_descr stdout_r; - outc = Unix.out_channel_of_descr stdin_w; - stop_marker = stop_marker; - killed = false; - start_time = now()} in - (* print_string ("Started process " ^ proc.id ^ "\n" ^ (stack_dump())); *) - all_procs := proc :: !all_procs; - proc - -let start_process - (id: string) (prog: string) (args: string list) - (stop_marker: string -> bool) : proc = - start_process' id prog args (Some stop_marker) - -let rec waitpid_ignore_signals pid = - try ignore (Unix.waitpid [] pid) - with Unix.Unix_error (Unix.EINTR, _, _) -> - waitpid_ignore_signals pid - -let kill_process (p: proc) = - if not p.killed then begin - (* Close the fds directly: close_in and close_out both call `flush`, - potentially forcing us to wait until p starts reading again. They - might have been closed already (e.g. `run_process`), so we - just `attempt` it. *) - let attempt f = - try f () with | _ -> () - in - attempt (fun () -> Unix.close (Unix.descr_of_in_channel p.inc)); - attempt (fun () -> Unix.close (Unix.descr_of_out_channel p.outc)); - (try Unix.kill p.pid Sys.sigkill - with Unix.Unix_error (Unix.ESRCH, _, _) -> ()); - (* Avoid zombie processes (Unix.close_process does the same thing. *) - waitpid_ignore_signals p.pid; - (* print_string ("Killed process " ^ p.id ^ "\n" ^ (stack_dump())); *) - p.killed <- true - end - -let kill_all () = - BatList.iter kill_process !all_procs - -let process_read_all_output (p: proc) = - (* Pass cleanup:false because kill_process closes both fds already. *) - BatIO.read_all (BatIO.input_channel ~autoclose:true ~cleanup:false p.inc) - -(** Feed `stdin` to `p`, and call `reader_fn` in a separate thread to read the - response. - - Signal handling makes this function fairly hairy. The usual design is to - launch a reader thread, then write to the process on the main thread and use - `Thread.join` to wait for the reader to complete. - - When we get a signal, Caml routes it to either of the threads. If it - reaches the reader thread, we're good: the reader thread is most likely - waiting in input_line at that point, and input_line polls for signals fairly - frequently. If the signal reaches the writer (main) thread, on the other - hand, we're toast: `Thread.join` isn't interruptible, so Caml will save the - signal until the child thread exits and `join` returns, and at that point the - Z3 query is complete and the signal is useless. - - There are three possible solutions to this problem: - 1. Use an interruptible version of Thread.join written in C - 2. Ensure that signals are always delivered to the reader thread - 3. Use a different synchronization mechanism between the reader and the writer. - - Option 1 is bad because building F* doesn't currently require a C compiler. - Option 2 is easy to implement with `Unix.sigprocmask`, but that isn't - available on Windows. Option 3 is what the code below does: it uses a pipe - and a 1-byte write as a way for the writer thread to wait on the reader - thread. That's why `reader_fn` is passed a `signal_exit` function. - - If a SIGINT reaches the reader, it should still call `signal_exit`. If - a SIGINT reaches the writer, it should make sure that the reader exits. - These two things are the responsibility of the caller of this function. **) - -let process_read_async p stdin reader_fn = - let fd_r, fd_w = Unix.pipe () in - BatPervasives.finally (fun () -> Unix.close fd_w; Unix.close fd_r) - (fun () -> - let wait_for_exit () = - ignore (Unix.read fd_r (Bytes.create 1) 0 1) in - let signal_exit () = - try ignore (Unix.write fd_w (Bytes.create 1) 0 1) - with (* ‘write’ will fail if called after the finalizer above *) - | Unix.Unix_error (Unix.EBADF, _, _) -> () in - - let write_input = function - | Some str -> output_string p.outc str; flush p.outc - | None -> () in - - (* In the following we can get a signal at any point; it's the caller's - responsibility to ensure that reader_fn will exit in that case *) - let t = Thread.create reader_fn signal_exit in - write_input stdin; - wait_for_exit (); - Thread.join t) () - -let run_process (id: string) (prog: string) (args: string list) (stdin: string option): string = - let p = start_process' id prog args None in - (match stdin with - | None -> () - | Some str -> output_string p.outc str); - flush p.outc; - close_out p.outc; - process_read_all_output p - -type read_result = EOF | SIGINT - -let ask_process - (p: proc) (stdin: string) - (exn_handler: unit -> string): string = - let result = ref None in - let out = Buffer.create 16 in - let stop_marker = BatOption.default (fun s -> false) p.stop_marker in - - let reader_fn signal_fn = - let rec loop p out = - let line = BatString.trim (input_line p.inc) in (* raises EOF *) - if not (stop_marker line) then - (Buffer.add_string out (line ^ "\n"); loop p out) in - (try loop p out - with | SigInt -> result := Some SIGINT - | End_of_file -> result := Some EOF); - signal_fn () in - - try - process_read_async p (Some stdin) reader_fn; - (match !result with - | Some EOF -> kill_process p; Buffer.add_string out (exn_handler ()) - | Some SIGINT -> raise SigInt - | None -> ()); - Buffer.contents out - with e -> (* Ensure that reader_fn gets an EOF and exits *) - kill_process p; raise e - let get_file_extension (fn:string) : string = snd (BatString.rsplit fn ".") let is_path_absolute path_str = let open Batteries.Incubator in @@ -355,80 +157,80 @@ let set_symmetric_difference ((s1, eq):'a set) ((s2, _):'a set) : 'a set = let set_eq ((s1, eq):'a set) ((s2, _):'a set) : bool = set_is_empty (set_symmetric_difference (s1, eq) (s2, eq)) -module StringOps = - struct - type t = string - let equal (x:t) (y:t) = x=y - let compare (x:t) (y:t) = BatString.compare x y - let hash (x:t) = BatHashtbl.hash x - end - -module StringHashtbl = BatHashtbl.Make(StringOps) -module StringMap = BatMap.Make(StringOps) - -type 'value smap = 'value StringHashtbl.t -let smap_create (i:Z.t) : 'value smap = StringHashtbl.create (Z.to_int i) -let smap_clear (s:('value smap)) = StringHashtbl.clear s -let smap_add (m:'value smap) k (v:'value) = StringHashtbl.replace m k v -let smap_of_list (l: (string * 'value) list) = - let s = StringHashtbl.create (BatList.length l) in - FStar_List.iter (fun (x,y) -> smap_add s x y) l; - s -let smap_try_find (m:'value smap) k = StringHashtbl.find_option m k -let smap_fold (m:'value smap) f a = StringHashtbl.fold f m a -let smap_remove (m:'value smap) k = StringHashtbl.remove m k -let smap_keys (m:'value smap) = smap_fold m (fun k _ acc -> k::acc) [] -let smap_copy (m:'value smap) = StringHashtbl.copy m -let smap_size (m:'value smap) = StringHashtbl.length m -let smap_iter (m:'value smap) f = StringHashtbl.iter f m - -exception PSMap_Found -type 'value psmap = 'value StringMap.t -let psmap_empty (_: unit) : 'value psmap = StringMap.empty -let psmap_add (map: 'value psmap) (key: string) (value: 'value) = StringMap.add key value map -let psmap_find_default (map: 'value psmap) (key: string) (dflt: 'value) = - StringMap.find_default dflt key map -let psmap_try_find (map: 'value psmap) (key: string) = - StringMap.Exceptionless.find key map -let psmap_fold (m:'value psmap) f a = StringMap.fold f m a -let psmap_find_map (m:'value psmap) f = - let res = ref None in - let upd k v = - let r = f k v in - if r <> None then (res := r; raise PSMap_Found) in - (try StringMap.iter upd m with PSMap_Found -> ()); - !res -let psmap_modify (m: 'value psmap) (k: string) (upd: 'value option -> 'value) = - StringMap.modify_opt k (fun vopt -> Some (upd vopt)) m - -let psmap_merge (m1: 'value psmap) (m2: 'value psmap) : 'value psmap = - psmap_fold m1 (fun k v m -> psmap_add m k v) m2 - -module ZHashtbl = BatHashtbl.Make(Z) -module ZMap = BatMap.Make(Z) - -type 'value imap = 'value ZHashtbl.t -let imap_create (i:Z.t) : 'value imap = ZHashtbl.create (Z.to_int i) -let imap_clear (s:('value imap)) = ZHashtbl.clear s -let imap_add (m:'value imap) k (v:'value) = ZHashtbl.replace m k v -let imap_of_list (l: (Z.t * 'value) list) = - let s = ZHashtbl.create (BatList.length l) in - FStar_List.iter (fun (x,y) -> imap_add s x y) l; - s -let imap_try_find (m:'value imap) k = ZHashtbl.find_option m k -let imap_fold (m:'value imap) f a = ZHashtbl.fold f m a -let imap_remove (m:'value imap) k = ZHashtbl.remove m k -let imap_keys (m:'value imap) = imap_fold m (fun k _ acc -> k::acc) [] -let imap_copy (m:'value imap) = ZHashtbl.copy m - -type 'value pimap = 'value ZMap.t -let pimap_empty (_: unit) : 'value pimap = ZMap.empty -let pimap_add (map: 'value pimap) (key: Z.t) (value: 'value) = ZMap.add key value map -let pimap_find_default (map: 'value pimap) (key: Z.t) (dflt: 'value) = - ZMap.find_default dflt key map -let pimap_try_find (map: 'value pimap) (key: Z.t) = - ZMap.Exceptionless.find key map -let pimap_fold (m:'value pimap) f a = ZMap.fold f m a +(* module StringOps = *) +(* struct *) +(* type t = string *) +(* let equal (x:t) (y:t) = x=y *) +(* let compare (x:t) (y:t) = BatString.compare x y *) +(* let hash (x:t) = BatHashtbl.hash x *) +(* end *) + +(* module StringHashtbl = BatHashtbl.Make(StringOps) *) +(* module StringMap = BatMap.Make(StringOps) *) + +(* type 'value smap = 'value StringHashtbl.t *) +(* let smap_create (i:Z.t) : 'value smap = StringHashtbl.create (Z.to_int i) *) +(* let smap_clear (s:('value smap)) = StringHashtbl.clear s *) +(* let smap_add (m:'value smap) k (v:'value) = StringHashtbl.replace m k v *) +(* let smap_of_list (l: (string * 'value) list) = *) +(* let s = StringHashtbl.create (BatList.length l) in *) +(* FStar_List.iter (fun (x,y) -> smap_add s x y) l; *) +(* s *) +(* let smap_try_find (m:'value smap) k = StringHashtbl.find_option m k *) +(* let smap_fold (m:'value smap) f a = StringHashtbl.fold f m a *) +(* let smap_remove (m:'value smap) k = StringHashtbl.remove m k *) +(* let smap_keys (m:'value smap) = smap_fold m (fun k _ acc -> k::acc) [] *) +(* let smap_copy (m:'value smap) = StringHashtbl.copy m *) +(* let smap_size (m:'value smap) = StringHashtbl.length m *) +(* let smap_iter (m:'value smap) f = StringHashtbl.iter f m *) + +(* exception PSMap_Found *) +(* type 'value psmap = 'value StringMap.t *) +(* let psmap_empty (_: unit) : 'value psmap = StringMap.empty *) +(* let psmap_add (map: 'value psmap) (key: string) (value: 'value) = StringMap.add key value map *) +(* let psmap_find_default (map: 'value psmap) (key: string) (dflt: 'value) = *) +(* StringMap.find_default dflt key map *) +(* let psmap_try_find (map: 'value psmap) (key: string) = *) +(* StringMap.Exceptionless.find key map *) +(* let psmap_fold (m:'value psmap) f a = StringMap.fold f m a *) +(* let psmap_find_map (m:'value psmap) f = *) +(* let res = ref None in *) +(* let upd k v = *) +(* let r = f k v in *) +(* if r <> None then (res := r; raise PSMap_Found) in *) +(* (try StringMap.iter upd m with PSMap_Found -> ()); *) +(* !res *) +(* let psmap_modify (m: 'value psmap) (k: string) (upd: 'value option -> 'value) = *) +(* StringMap.modify_opt k (fun vopt -> Some (upd vopt)) m *) + +(* let psmap_merge (m1: 'value psmap) (m2: 'value psmap) : 'value psmap = *) +(* psmap_fold m1 (fun k v m -> psmap_add m k v) m2 *) + +(* module ZHashtbl = BatHashtbl.Make(Z) *) +(* module ZMap = BatMap.Make(Z) *) + +(* type 'value imap = 'value ZHashtbl.t *) +(* let imap_create (i:Z.t) : 'value imap = ZHashtbl.create (Z.to_int i) *) +(* let imap_clear (s:('value imap)) = ZHashtbl.clear s *) +(* let imap_add (m:'value imap) k (v:'value) = ZHashtbl.replace m k v *) +(* let imap_of_list (l: (Z.t * 'value) list) = *) +(* let s = ZHashtbl.create (BatList.length l) in *) +(* FStar_List.iter (fun (x,y) -> imap_add s x y) l; *) +(* s *) +(* let imap_try_find (m:'value imap) k = ZHashtbl.find_option m k *) +(* let imap_fold (m:'value imap) f a = ZHashtbl.fold f m a *) +(* let imap_remove (m:'value imap) k = ZHashtbl.remove m k *) +(* let imap_keys (m:'value imap) = imap_fold m (fun k _ acc -> k::acc) [] *) +(* let imap_copy (m:'value imap) = ZHashtbl.copy m *) + +(* type 'value pimap = 'value ZMap.t *) +(* let pimap_empty (_: unit) : 'value pimap = ZMap.empty *) +(* let pimap_add (map: 'value pimap) (key: Z.t) (value: 'value) = ZMap.add key value map *) +(* let pimap_find_default (map: 'value pimap) (key: Z.t) (dflt: 'value) = *) +(* ZMap.find_default dflt key map *) +(* let pimap_try_find (map: 'value pimap) (key: Z.t) = *) +(* ZMap.Exceptionless.find key map *) +(* let pimap_fold (m:'value pimap) f a = ZMap.fold f m a *) (* restore pre-2.11 BatString.nsplit behavior, see https://github.com/ocaml-batteries-team/batteries-included/issues/845 *) @@ -563,7 +365,7 @@ let replace_char (s:string) c1 c2 = BatUTF8.map (fun x -> if x = c1 then c2 else x) s let replace_chars (s:string) c (by:string) = BatString.replace_chars (fun x -> if x = Char.chr c then by else BatString.of_char x) s -let hashcode s = Z.of_int (StringOps.hash s) +(* let hashcode s = Z.of_int (StringOps.hash s) *) let compare s1 s2 = Z.of_int (BatString.compare s1 s2) let split s sep = BatString.split_on_string sep s let splitlines s = split s "\n" @@ -631,14 +433,6 @@ let remove_dups f l = | _ -> out in aux [] l -let is_none = function - | None -> true - | Some _ -> false - -let is_some = function - | None -> false - | Some _ -> true - let must = function | Some x -> x | None -> failwith "Empty option" @@ -647,86 +441,20 @@ let dflt x = function | None -> x | Some x -> x -let find_opt f l = - let rec aux = function - | [] -> None - | hd::tl -> if f hd then Some hd else aux tl in - aux l - -(* JP: why so many duplicates? :'( *) -let sort_with = FStar_List.sortWith - let bind_opt opt f = match opt with | None -> None | Some x -> f x -let catch_opt opt f = - match opt with - | Some x -> opt - | None -> f () - let map_opt opt f = match opt with | None -> None | Some x -> Some (f x) -let iter_opt opt f = - ignore (map_opt opt f) - -let rec find_map l f = - match l with - | [] -> None - | x::tl -> - match f x with - | None -> find_map tl f - | y -> y - let try_find f l = BatList.find_opt f l -let try_find_index f l = - let rec aux i = function - | [] -> None - | hd::tl -> if f hd then Some (Z.of_int i) else aux (i+1) tl in - aux 0 l - -let fold_map f state s = - let fold (state, acc) x = - let state, v = f state x in (state, v :: acc) in - let (state, rs) = BatList.fold_left fold (state, []) s in - (state, BatList.rev rs) - -let choose_map f state s = - let fold (state, acc) x = - match f state x with - | state, None -> (state, acc) - | state, Some v -> (state, v :: acc) in - let (state, rs) = BatList.fold_left fold (state, []) s in - (state, BatList.rev rs) - let for_all f l = BatList.for_all f l let for_some f l = BatList.exists f l -let forall_exists rel l1 l2 = - for_all (fun x -> for_some (rel x) l2) l1 -let multiset_equiv rel l1 l2 = - BatList.length l1 = BatList.length l2 && forall_exists rel l1 l2 -let take p l = - let rec take_aux acc = function - | [] -> l, [] - | x::xs when p x -> take_aux (x::acc) xs - | x::xs -> List.rev acc, x::xs - in take_aux [] l - -let rec fold_flatten f acc l = - match l with - | [] -> acc - | x :: xs -> let acc, xs' = f acc x in fold_flatten f acc (xs' @ xs) - -let add_unique f x l = - if for_some (f x) l then - l - else - x::l let first_N n l = let n = Z.to_int n in @@ -749,528 +477,4 @@ let prefix l = | hd::tl -> BatList.rev tl, hd | _ -> failwith "impossible" -let prefix_until f l = - let rec aux prefix = function - | [] -> None - | hd::tl -> - if f hd then Some (BatList.rev prefix, hd, tl) - else aux (hd::prefix) tl in - aux [] l - -let string_to_ascii_bytes (s:string) : char array = - BatArray.of_list (BatString.explode s) -let ascii_bytes_to_string (b:char array) : string = - BatString.implode (BatArray.to_list b) -let mk_ref a = FStar_ST.alloc a - -(* A simple state monad *) -type ('s,'a) state = 's -> ('a*'s) -let get : ('s,'s) state = fun s -> (s,s) -let upd (f:'s -> 's) : ('s,unit) state = fun s -> ((), f s) -let put (s:'s) : ('s,unit) state = fun _ -> ((), s) -let ret (x:'a) : ('s,'a) state = fun s -> (x, s) -let bind (sa:('s,'a) state) (f : 'a -> ('s,'b) state) : ('s,'b) state = - fun s1 -> let (a, s2) = sa s1 in f a s2 -let (>>) s f = bind s f -let run_st init (s:('s,'a) state) = s init - -let rec stmap (l:'a list) (f: 'a -> ('s,'b) state) : ('s, ('b list)) state = - match l with - | [] -> ret [] - | hd::tl -> bind (f hd) - (fun b -> - let stl = stmap tl f in - bind stl (fun tl -> ret (b::tl))) - -let stmapi (l:'a list) (f:int -> 'a -> ('s, 'b) state) : ('s, ('b list)) state = - let rec aux i l = - match l with - | [] -> ret [] - | hd::tl -> - bind (f i hd) - (fun b -> - let stl = aux (i + 1) tl in - bind stl (fun tl -> ret (b::tl))) in - aux 0 l - -let rec stiter (l:'a list) (f: 'a -> ('s,unit) state) : ('s,unit) state = - match l with - | [] -> ret () - | hd::tl -> bind (f hd) (fun () -> stiter tl f) - -let rec stfoldr_pfx (l:'a list) (f: 'a list -> 'a -> ('s,unit) state) : ('s,unit) state = - match l with - | [] -> ret () - | hd::tl -> (stfoldr_pfx tl f) >> (fun _ -> f tl hd) - -let rec stfold (init:'b) (l:'a list) (f: 'b -> 'a -> ('s,'b) state) : ('s,'b) state = - match l with - | [] -> ret init - | hd::tl -> (f init hd) >> (fun next -> stfold next tl f) - -type file_handle = out_channel -let open_file_for_writing (fn:string) : file_handle = open_out_bin fn -let append_to_file (fh:file_handle) s = fpr fh "%s\n" s; flush fh -let close_file (fh:file_handle) = close_out fh -let write_file (fn:string) s = - let fh = open_file_for_writing fn in - append_to_file fh s; - close_file fh -let copy_file input_name output_name = - (* see https://ocaml.github.io/ocamlunix/ocamlunix.html#sec33 *) - let open Unix in - let buffer_size = 8192 in - let buffer = Bytes.create buffer_size in - let fd_in = openfile input_name [O_RDONLY] 0 in - let fd_out = openfile output_name [O_WRONLY; O_CREAT; O_TRUNC] 0o666 in - let rec copy_loop () = - match read fd_in buffer 0 buffer_size with - | 0 -> () - | r -> ignore (write fd_out buffer 0 r); copy_loop () - in - copy_loop (); - close fd_in; - close fd_out -let flush_file (fh:file_handle) = flush fh -let delete_file (fn:string) = Sys.remove fn -let file_get_contents f = - let ic = open_in_bin f in - let l = in_channel_length ic in - let s = really_input_string ic l in - close_in ic; - s -let file_get_lines f = - let ic = open_in f in - let rec aux accu = - let l = - try - Some (input_line ic) - with - | End_of_file -> None - in - match l with - | None -> accu - | Some l -> aux (l::accu) - in - let l = aux [] in - close_in ic; - List.rev l -let concat_dir_filename d f = Filename.concat d f -let mkdir clean nm = - let remove_all_in_dir nm = - let open Sys in - Array.iter remove (Array.map (concat_dir_filename nm) (readdir nm)) in - let open Unix in - (match Sys.os_type with - | "Unix" -> ignore (umask 0o002) - | _ -> (* unimplemented*) ()); - try mkdir nm 0o777 - with Unix_error (EEXIST,_,_) -> - if clean then remove_all_in_dir nm - -let for_range lo hi f = - for i = Z.to_int lo to Z.to_int hi do - f (Z.of_int i) - done - - -let incr r = FStar_ST.(Z.(write r (read r + one))) -let decr r = FStar_ST.(Z.(write r (read r - one))) -let geq (i:int) (j:int) = i >= j - -let get_exec_dir () = Filename.dirname (Sys.executable_name) -let expand_environment_variable x = try Some (Sys.getenv x) with Not_found -> None - -let physical_equality (x:'a) (y:'a) = x == y -let check_sharing a b msg = if physical_equality a b then print1 "Sharing OK: %s\n" msg else print1 "Sharing broken in %s\n" msg - -type oWriter = { - write_byte: char -> unit; - write_bool: bool -> unit; - write_int: int -> unit; - write_int32: int32 -> unit; - write_int64: int64 -> unit; - write_char: char -> unit; - write_double: float -> unit; - write_bytearray: char array -> unit; - write_string: string -> unit; - - close: unit -> unit -} - -type oReader = { - read_byte: unit -> char; - read_bool: unit -> bool; - read_int: unit -> int; - read_int32: unit -> int32; - read_int64: unit -> int64; - read_char: unit -> char; - read_double: unit -> float; - read_bytearray: unit -> char array; - read_string: unit -> string; - - close: unit -> unit -} - -module MkoReader = struct - let read_byte r x = r.read_byte x - let read_bool r x = r.read_bool x - let read_int r x = r.read_int32 x - let read_int32 r x = r.read_int32 x - let read_int64 r x = r.read_int64 x - let read_char r x = r.read_char x - let read_double r x = r.read_double x - let read_bytearray r x = r.read_bytearray x - let read_string r x = r.read_string x - - let close r x = r.close x -end - -module MkoWriter = struct - let write_byte w x = w.write_byte x - let write_bool w x = w.write_bool x - let write_int w x = w.write_int32 x - let write_int32 w x = w.write_int32 x - let write_int64 w x = w.write_int64 x - let write_char w x = w.write_char x - let write_double w x = w.write_double x - let write_bytearray w x = w.write_bytearray x - let write_string w x = w.write_string x - - let close w x = w.close x -end - -(* - * TODO: these functions need to be filled in - *) -let get_owriter (filename:string) : oWriter = { - write_byte = (fun _ -> ()); - write_bool = (fun _ -> ()); - write_int = (fun _ -> ()); - write_int32 = (fun _ -> ()); - write_int64 = (fun _ -> ()); - write_char = (fun _ -> ()); - write_double = (fun _ -> ()); - write_bytearray = (fun _ -> ()); - write_string = (fun _ -> ()); - - close = (fun _ -> ()); -} - -let get_oreader (filename:string) : oReader = { - read_byte = (fun _ -> 'a'); - read_bool = (fun _ -> true); - read_int = (fun _ -> 0); - read_int32 = (fun _ -> failwith "NYI"); - read_int64 = (fun _ -> 0L); - read_char = (fun _ -> 'a'); - read_double = (fun _ -> 0.0); - read_bytearray = (fun _ -> [||]); - read_string = (fun _ -> ""); - - close = (fun _ -> ()); -} - -let getcwd = Sys.getcwd - -let readdir dir = "." :: ".." :: Array.to_list (Sys.readdir dir) - -let paths_to_same_file f g = - let open Unix in - let { st_dev = i; st_ino = j } = stat f in - let { st_dev = i'; st_ino = j' } = stat g in - (i,j) = (i',j') - -let file_exists = Sys.file_exists -(* Sys.is_directory raises Sys_error if the path does not exist *) -let is_directory f = Sys.file_exists f && Sys.is_directory f - - -let basename = Filename.basename -let dirname = Filename.dirname -let print_endline = print_endline - -let map_option f opt = BatOption.map f opt - -let save_value_to_file (fname:string) value = - (* BatFile.with_file_out uses Unix.openfile (which isn't available in - js_of_ocaml) instead of Pervasives.open_out, so we don't use it here. *) - let channel = open_out_bin fname in - BatPervasives.finally - (fun () -> close_out channel) - (fun channel -> output_value channel value) - channel - -let load_value_from_file (fname:string) = - (* BatFile.with_file_in uses Unix.openfile (which isn't available in - js_of_ocaml) instead of Pervasives.open_in, so we don't use it here. *) - try - let channel = open_in_bin fname in - BatPervasives.finally - (fun () -> close_in channel) - (fun channel -> Some (input_value channel)) - channel - with | _ -> None - -let save_2values_to_file (fname:string) value1 value2 = - try - let channel = open_out_bin fname in - BatPervasives.finally - (fun () -> close_out channel) - (fun channel -> - output_value channel value1; - output_value channel value2) - channel - with - | e -> delete_file fname; - raise e - -let load_2values_from_file (fname:string) = - try - let channel = open_in_bin fname in - BatPervasives.finally - (fun () -> close_in channel) - (fun channel -> - let v1 = input_value channel in - let v2 = input_value channel in - Some (v1, v2)) - channel - with | _ -> None - -let print_exn e = - Printexc.to_string e - -let digest_of_file = - let cache = smap_create (Z.of_int 101) in - fun (fname:string) -> - match smap_try_find cache fname with - | Some dig -> dig - | None -> - let dig = BatDigest.file fname in - smap_add cache fname dig; - dig - -let digest_of_string (s:string) = - BatDigest.to_hex (BatDigest.string s) - -(* Precondition: file exists *) -let touch_file (fname:string) : unit = - (* Sets access and modification times to current time *) - Unix.utimes fname 0.0 0.0 - -let ensure_decimal s = Z.to_string (Z.of_string s) - -let measure_execution_time tag f = - let t = Sys.time () in - let retv = f () in - print2 "Execution time of %s: %s ms\n" tag (string_of_float (1000.0 *. (Sys.time() -. t))); - retv - -let return_execution_time f = - let t1 = Sys.time () in - let retv = f () in - let t2 = Sys.time () in - (retv, 1000.0 *. (t2 -. t1)) - -(** Hints. *) -type hint = { - hint_name:string; - hint_index:Z.t; - fuel:Z.t; - ifuel:Z.t; - unsat_core:string list option; - query_elapsed_time:Z.t; - hash:string option -} - -type hints = hint option list - -type hints_db = { - module_digest:string; - hints: hints -} - -type hints_read_result = - | HintsOK of hints_db - | MalformedJson - | UnableToOpen - -let write_hints (filename: string) (hints: hints_db): unit = - let json = `List [ - `String hints.module_digest; - `List (List.map (function - | None -> `Null - | Some { hint_name; hint_index; fuel; ifuel; unsat_core; query_elapsed_time; hash } -> - `List [ - `String hint_name; - `Int (Z.to_int hint_index); - `Int (Z.to_int fuel); - `Int (Z.to_int ifuel); - (match unsat_core with - | None -> `Null - | Some strings -> - `List (List.map (fun s -> `String s) strings)); - `Int (Z.to_int query_elapsed_time); - `String (match hash with | Some(h) -> h | _ -> "") - ] - ) hints.hints) - ] in - let channel = open_out_bin filename in - BatPervasives.finally - (fun () -> close_out channel) - (fun channel -> Yojson.Safe.pretty_to_channel channel json) - channel - -let read_hints (filename: string) : hints_read_result = - let mk_hint nm ix fuel ifuel unsat_core time hash_opt = { - hint_name = nm; - hint_index = Z.of_int ix; - fuel = Z.of_int fuel; - ifuel = Z.of_int ifuel; - unsat_core = begin - match unsat_core with - | `Null -> - None - | `List strings -> - Some (List.map (function - | `String s -> s - | _ -> raise Exit) - strings) - | _ -> - raise Exit - end; - query_elapsed_time = Z.of_int time; - hash = hash_opt - } - in - try - let chan = open_in filename in - let json = Yojson.Safe.from_channel chan in - close_in chan; - HintsOK ( - match json with - | `List [ - `String module_digest; - `List hints - ] -> { - module_digest; - hints = List.map (function - | `Null -> None - | `List [ `String hint_name; - `Int hint_index; - `Int fuel; - `Int ifuel; - unsat_core; - `Int query_elapsed_time ] -> - (* This case is for dealing with old-style hint files - that lack a query-hashes field. We should remove this - case once we definitively remove support for old hints *) - Some (mk_hint hint_name hint_index fuel ifuel unsat_core query_elapsed_time None) - | `List [ `String hint_name; - `Int hint_index; - `Int fuel; - `Int ifuel; - unsat_core; - `Int query_elapsed_time; - `String hash ] -> - let hash_opt = if hash <> "" then Some(hash) else None in - Some (mk_hint hint_name hint_index fuel ifuel unsat_core query_elapsed_time hash_opt) - | _ -> - raise Exit - ) hints - } - | _ -> - raise Exit - ) - with - | Exit -> - MalformedJson - | Sys_error _ -> - UnableToOpen - -(** Interactive protocol **) - -exception UnsupportedJson - -let json_of_yojson yjs: json option = - let rec aux yjs = - match yjs with - | `Null -> JsonNull - | `Bool b -> JsonBool b - | `Int i -> JsonInt (Z.of_int i) - | `String s -> JsonStr s - | `List l -> JsonList (List.map aux l) - | `Assoc a -> JsonAssoc (List.map (fun (k, v) -> (k, aux v)) a) - | _ -> raise UnsupportedJson in - try Some (aux yjs) with UnsupportedJson -> None - -let rec yojson_of_json js = - match js with - | JsonNull -> `Null - | JsonBool b -> `Bool b - | JsonInt i -> `Int (Z.to_int i) - | JsonStr s -> `String s - | JsonList l -> `List (List.map yojson_of_json l) - | JsonAssoc a -> `Assoc (List.map (fun (k, v) -> (k, yojson_of_json v)) a) - -let json_of_string str : json option = - let open Yojson.Basic in - try - json_of_yojson (Yojson.Basic.from_string str) - with Yojson.Json_error _ -> None - -let string_of_json json = - Yojson.Basic.to_string (yojson_of_json json) - -(* Outside of this file the reference to FStar_Util.ref must use the following combinators *) -(* Export it at the end of the file so that we don't break other internal uses of ref *) -type 'a ref = 'a FStar_Monotonic_Heap.ref -let read = FStar_ST.read -let write = FStar_ST.write -let (!) = FStar_ST.read -let (:=) = FStar_ST.write - -let marshal (x:'a) : string = Marshal.to_string x [] -let unmarshal (x:string) : 'a = Marshal.from_string x 0 - -type signedness = | Unsigned | Signed -type width = | Int8 | Int16 | Int32 | Int64 - -let rec z_pow2 n = - if n = Z.zero then Z.one - else Z.mul (Z.of_string "2") (z_pow2 (Z.sub n Z.one)) - -let bounds signedness width = - let n = - match width with - | Int8 -> Z.of_string "8" - | Int16 -> Z.of_string "16" - | Int32 -> Z.of_string "32" - | Int64 -> Z.of_string "64" - in - let lower, upper = - match signedness with - | Unsigned -> - Z.zero, Z.sub (z_pow2 n) Z.one - | Signed -> - let upper = z_pow2 (Z.sub n Z.one) in - Z.neg upper, Z.sub upper Z.one - in - lower, upper - -let within_bounds repr signedness width = - let lower, upper = bounds signedness width in - let value = Z.of_string (ensure_decimal repr) in - Z.leq lower value && Z.leq value upper - -let print_array (f: 'a -> string) - (s: 'a array) - : string - = let ls = Array.fold_left (fun out a -> f a :: out) [] s in - format1 "[| %s |]" (String.concat "; " (List.rev ls)) - -let array_of_list (l:'a list) = FStar_ImmutableArray_Base.of_list l - -let array_length (l:'a FStar_ImmutableArray_Base.t) = FStar_ImmutableArray_Base.length l - -let array_index (l:'a FStar_ImmutableArray_Base.t) (i:Z.t) = FStar_ImmutableArray_Base.index l i +let mk_ref a = ref a diff --git a/engine/backends/fstar/fstar-surface-ast/FStar_Const.ml b/engine/backends/fstar/fstar-surface-ast/FStar_Const.ml index a1fcff708..5223a3acf 100644 --- a/engine/backends/fstar/fstar-surface-ast/FStar_Const.ml +++ b/engine/backends/fstar/fstar-surface-ast/FStar_Const.ml @@ -2,26 +2,12 @@ open Prims type signedness = | Unsigned | Signed [@@deriving yojson,show] -let (uu___is_Unsigned : signedness -> Prims.bool) = - fun projectee -> match projectee with | Unsigned -> true | uu___ -> false -let (uu___is_Signed : signedness -> Prims.bool) = - fun projectee -> match projectee with | Signed -> true | uu___ -> false type width = | Int8 | Int16 | Int32 | Int64 | Sizet [@@deriving yojson,show] -let (uu___is_Int8 : width -> Prims.bool) = - fun projectee -> match projectee with | Int8 -> true | uu___ -> false -let (uu___is_Int16 : width -> Prims.bool) = - fun projectee -> match projectee with | Int16 -> true | uu___ -> false -let (uu___is_Int32 : width -> Prims.bool) = - fun projectee -> match projectee with | Int32 -> true | uu___ -> false -let (uu___is_Int64 : width -> Prims.bool) = - fun projectee -> match projectee with | Int64 -> true | uu___ -> false -let (uu___is_Sizet : width -> Prims.bool) = - fun projectee -> match projectee with | Sizet -> true | uu___ -> false type sconst = | Const_effect | Const_unit @@ -36,61 +22,6 @@ type sconst = | Const_range of FStar_Compiler_Range.range | Const_reify of FStar_Ident.lid FStar_Pervasives_Native.option | Const_reflect of FStar_Ident.lid [@@deriving yojson,show] -let (uu___is_Const_effect : sconst -> Prims.bool) = - fun projectee -> - match projectee with | Const_effect -> true | uu___ -> false -let (uu___is_Const_unit : sconst -> Prims.bool) = - fun projectee -> match projectee with | Const_unit -> true | uu___ -> false -let (uu___is_Const_bool : sconst -> Prims.bool) = - fun projectee -> - match projectee with | Const_bool _0 -> true | uu___ -> false -let (__proj__Const_bool__item___0 : sconst -> Prims.bool) = - fun projectee -> match projectee with | Const_bool _0 -> _0 -let (uu___is_Const_int : sconst -> Prims.bool) = - fun projectee -> - match projectee with | Const_int _0 -> true | uu___ -> false -let (__proj__Const_int__item___0 : - sconst -> - (Prims.string * (signedness * width) FStar_Pervasives_Native.option)) - = fun projectee -> match projectee with | Const_int _0 -> _0 -let (uu___is_Const_char : sconst -> Prims.bool) = - fun projectee -> - match projectee with | Const_char _0 -> true | uu___ -> false -let (__proj__Const_char__item___0 : sconst -> FStar_BaseTypes.char) = - fun projectee -> match projectee with | Const_char _0 -> _0 -let (uu___is_Const_real : sconst -> Prims.bool) = - fun projectee -> - match projectee with | Const_real _0 -> true | uu___ -> false -let (__proj__Const_real__item___0 : sconst -> Prims.string) = - fun projectee -> match projectee with | Const_real _0 -> _0 -let (uu___is_Const_string : sconst -> Prims.bool) = - fun projectee -> - match projectee with | Const_string _0 -> true | uu___ -> false -let (__proj__Const_string__item___0 : - sconst -> (Prims.string * FStar_Compiler_Range.range)) = - fun projectee -> match projectee with | Const_string _0 -> _0 -let (uu___is_Const_range_of : sconst -> Prims.bool) = - fun projectee -> - match projectee with | Const_range_of -> true | uu___ -> false -let (uu___is_Const_set_range_of : sconst -> Prims.bool) = - fun projectee -> - match projectee with | Const_set_range_of -> true | uu___ -> false -let (uu___is_Const_range : sconst -> Prims.bool) = - fun projectee -> - match projectee with | Const_range _0 -> true | uu___ -> false -let (__proj__Const_range__item___0 : sconst -> FStar_Compiler_Range.range) = - fun projectee -> match projectee with | Const_range _0 -> _0 -let (uu___is_Const_reify : sconst -> Prims.bool) = - fun projectee -> - match projectee with | Const_reify _0 -> true | uu___ -> false -let (__proj__Const_reify__item___0 : - sconst -> FStar_Ident.lid FStar_Pervasives_Native.option) = - fun projectee -> match projectee with | Const_reify _0 -> _0 -let (uu___is_Const_reflect : sconst -> Prims.bool) = - fun projectee -> - match projectee with | Const_reflect _0 -> true | uu___ -> false -let (__proj__Const_reflect__item___0 : sconst -> FStar_Ident.lid) = - fun projectee -> match projectee with | Const_reflect _0 -> _0 let (eq_const : sconst -> sconst -> Prims.bool) = fun c1 -> fun c2 -> @@ -103,46 +34,3 @@ let (eq_const : sconst -> sconst -> Prims.bool) = | (Const_reflect l1, Const_reflect l2) -> FStar_Ident.lid_equals l1 l2 | (Const_reify uu___, Const_reify uu___1) -> true | uu___ -> c1 = c2 -let rec (pow2 : FStar_BigInt.bigint -> FStar_BigInt.bigint) = - fun x -> - let uu___ = FStar_BigInt.eq_big_int x FStar_BigInt.zero in - if uu___ - then FStar_BigInt.one - else - (let uu___2 = let uu___3 = FStar_BigInt.pred_big_int x in pow2 uu___3 in - FStar_BigInt.mult_big_int FStar_BigInt.two uu___2) -let (bounds : - signedness -> width -> (FStar_BigInt.bigint * FStar_BigInt.bigint)) = - fun signedness1 -> - fun width1 -> - let n = - match width1 with - | Int8 -> FStar_BigInt.big_int_of_string "8" - | Int16 -> FStar_BigInt.big_int_of_string "16" - | Int32 -> FStar_BigInt.big_int_of_string "32" - | Int64 -> FStar_BigInt.big_int_of_string "64" - | Sizet -> FStar_BigInt.big_int_of_string "16" in - let uu___ = - match signedness1 with - | Unsigned -> - let uu___1 = - let uu___2 = pow2 n in FStar_BigInt.pred_big_int uu___2 in - (FStar_BigInt.zero, uu___1) - | Signed -> - let upper = - let uu___1 = FStar_BigInt.pred_big_int n in pow2 uu___1 in - let uu___1 = FStar_BigInt.minus_big_int upper in - let uu___2 = FStar_BigInt.pred_big_int upper in (uu___1, uu___2) in - match uu___ with | (lower, upper) -> (lower, upper) -let (within_bounds : Prims.string -> signedness -> width -> Prims.bool) = - fun repr -> - fun signedness1 -> - fun width1 -> - let uu___ = bounds signedness1 width1 in - match uu___ with - | (lower, upper) -> - let value = - let uu___1 = FStar_Compiler_Util.ensure_decimal repr in - FStar_BigInt.big_int_of_string uu___1 in - (FStar_BigInt.le_big_int lower value) && - (FStar_BigInt.le_big_int value upper) \ No newline at end of file diff --git a/engine/backends/fstar/fstar-surface-ast/FStar_Errors.ml b/engine/backends/fstar/fstar-surface-ast/FStar_Errors.ml index 461ed330e..043b26699 100644 --- a/engine/backends/fstar/fstar-surface-ast/FStar_Errors.ml +++ b/engine/backends/fstar/fstar-surface-ast/FStar_Errors.ml @@ -228,15 +228,7 @@ exception Empty_frag let (uu___is_Empty_frag : Prims.exn -> Prims.bool) = fun projectee -> match projectee with | Empty_frag -> true | uu___ -> false let (ctx_string : Prims.string Prims.list -> Prims.string) = - fun ctx -> - let uu___ = FStar_Options.error_contexts () in - if uu___ - then - let uu___1 = - FStar_Compiler_Effect.op_Bar_Greater ctx - (FStar_Compiler_List.map (fun s -> FStar_String.op_Hat "\n> " s)) in - FStar_Compiler_Effect.op_Bar_Greater uu___1 (FStar_String.concat "") - else "" + fun ctx -> "" let (issue_message : issue -> Prims.string) = fun i -> let uu___ = ctx_string i.issue_ctx in @@ -335,13 +327,12 @@ let (mk_default_handler : Prims.bool -> error_handler) = else (); (match e.issue_level with | EInfo -> print_issue e - | uu___2 when print && (FStar_Options.debug_any ()) -> print_issue e | uu___2 -> let uu___3 = let uu___4 = FStar_Compiler_Effect.op_Bang issues in e :: uu___4 in FStar_Compiler_Effect.op_Colon_Equals issues uu___3); (let uu___3 = - (FStar_Options.defensive_abort ()) && + (false) && (e.issue_number = (FStar_Pervasives_Native.Some defensive_errno)) in if uu___3 then failwith "Aborting due to --defensive abort" else ()) in let count_errors uu___ = FStar_Compiler_Effect.op_Bang err_count in @@ -394,30 +385,15 @@ let (wrapped_eh_add_one : error_handler -> issue -> unit) = fun h -> fun issue1 -> h.eh_add_one issue1; - if issue1.issue_level <> EInfo - then - ((let uu___2 = - let uu___3 = - FStar_Compiler_Effect.op_Bang FStar_Options.abort_counter in - uu___3 - Prims.int_one in - FStar_Compiler_Effect.op_Colon_Equals FStar_Options.abort_counter - uu___2); - (let uu___2 = - let uu___3 = - FStar_Compiler_Effect.op_Bang FStar_Options.abort_counter in - uu___3 = Prims.int_zero in - if uu___2 then failwith "Aborting due to --abort_on" else ())) - else () + () let (add_one : issue -> unit) = fun issue1 -> - FStar_Compiler_Util.atomically - (fun uu___ -> + ( let uu___1 = FStar_Compiler_Effect.op_Bang current_handler in wrapped_eh_add_one uu___1 issue1) let (add_many : issue Prims.list -> unit) = fun issues -> - FStar_Compiler_Util.atomically - (fun uu___ -> + ( let uu___1 = let uu___2 = FStar_Compiler_Effect.op_Bang current_handler in wrapped_eh_add_one uu___2 in @@ -483,8 +459,7 @@ let (get_ctx : unit -> Prims.string Prims.list) = let (diag : FStar_Compiler_Range.range -> Prims.string -> unit) = fun r -> fun msg -> - let uu___ = FStar_Options.debug_any () in - if uu___ + if false then add_one (mk_issue EInfo (FStar_Pervasives_Native.Some r) msg @@ -495,72 +470,28 @@ let (warn_unsafe_options : Prims.string -> unit) = fun rng_opt -> - fun msg -> - let uu___ = FStar_Options.report_assumes () in - match uu___ with - | FStar_Pervasives_Native.Some "warn" -> - let uu___1 = - let uu___2 = - FStar_String.op_Hat - "Every use of this option triggers a warning: " msg in - mk_issue EWarning rng_opt uu___2 - (FStar_Pervasives_Native.Some warn_on_use_errno) [] in - add_one uu___1 - | FStar_Pervasives_Native.Some "error" -> - let uu___1 = - let uu___2 = - FStar_String.op_Hat - "Every use of this option triggers an error: " msg in - mk_issue EError rng_opt uu___2 - (FStar_Pervasives_Native.Some warn_on_use_errno) [] in - add_one uu___1 - | uu___1 -> () + fun msg -> () let (set_option_warning_callback_range : FStar_Compiler_Range.range FStar_Pervasives_Native.option -> unit) = fun ropt -> - FStar_Options.set_option_warning_callback (warn_unsafe_options ropt) + () + (* FStar_Options.set_option_warning_callback (warn_unsafe_options ropt) *) let (uu___279 : (((Prims.string -> FStar_Errors_Codes.error_setting Prims.list) -> unit) * (unit -> FStar_Errors_Codes.error_setting Prims.list))) = let parser_callback = FStar_Compiler_Util.mk_ref FStar_Pervasives_Native.None in - let error_flags = FStar_Compiler_Util.smap_create (Prims.of_int (10)) in - let set_error_flags uu___ = - let parse s = - let uu___1 = FStar_Compiler_Effect.op_Bang parser_callback in - match uu___1 with - | FStar_Pervasives_Native.None -> - failwith "Callback for parsing warn_error strings is not set" - | FStar_Pervasives_Native.Some f -> f s in - let we = FStar_Options.warn_error () in - try - (fun uu___1 -> - match () with - | () -> - let r = parse we in - (FStar_Compiler_Util.smap_add error_flags we - (FStar_Pervasives_Native.Some r); - FStar_Getopt.Success)) () - with - | Invalid_warn_error_setting msg -> - (FStar_Compiler_Util.smap_add error_flags we - FStar_Pervasives_Native.None; - (let uu___3 = - FStar_String.op_Hat "Invalid --warn_error setting: " msg in - FStar_Getopt.Error uu___3)) in + (* let error_flags = FStar_Compiler_Util.smap_create (Prims.of_int (10)) in *) + let set_error_flags uu___ = () in let get_error_flags uu___ = - let we = FStar_Options.warn_error () in - let uu___1 = FStar_Compiler_Util.smap_try_find error_flags we in - match uu___1 with - | FStar_Pervasives_Native.Some (FStar_Pervasives_Native.Some w) -> w - | uu___2 -> FStar_Errors_Codes.default_settings in + FStar_Errors_Codes.default_settings in let set_callbacks f = FStar_Compiler_Effect.op_Colon_Equals parser_callback - (FStar_Pervasives_Native.Some f); - FStar_Options.set_error_flags_callback set_error_flags; - FStar_Options.set_option_warning_callback - (warn_unsafe_options FStar_Pervasives_Native.None) in + (FStar_Pervasives_Native.Some f) + (* FStar_Options.set_option_warning_callback *) + (* (warn_unsafe_options FStar_Pervasives_Native.None) *) + in (set_callbacks, get_error_flags) let (t_set_parse_warn_error : (Prims.string -> FStar_Errors_Codes.error_setting Prims.list) -> unit) = @@ -581,29 +512,31 @@ let (lookup : | (v, level, i) -> let with_level level1 = (v, level1, i) in (match v with - | FStar_Errors_Codes.Warning_Defensive when - (FStar_Options.defensive_error ()) || - (FStar_Options.defensive_abort ()) - -> with_level FStar_Errors_Codes.CAlwaysError - | FStar_Errors_Codes.Warning_WarnOnUse -> - let level' = - let uu___1 = FStar_Options.report_assumes () in - match uu___1 with - | FStar_Pervasives_Native.None -> level - | FStar_Pervasives_Native.Some "warn" -> - (match level with - | FStar_Errors_Codes.CSilent -> - FStar_Errors_Codes.CWarning - | uu___2 -> level) - | FStar_Pervasives_Native.Some "error" -> - (match level with - | FStar_Errors_Codes.CWarning -> - FStar_Errors_Codes.CError - | FStar_Errors_Codes.CSilent -> FStar_Errors_Codes.CError - | uu___2 -> level) - | FStar_Pervasives_Native.Some uu___2 -> level in - with_level level' | uu___1 -> with_level level) + +let raise_error : + 'a . + (FStar_Errors_Codes.raw_error * Prims.string) -> + FStar_Compiler_Range.range -> 'a + = + fun uu___ -> + fun r -> + match uu___ with + | (e, msg) -> + let uu___1 = + let uu___2 = + let uu___3 = error_context.get () in (e, msg, r, uu___3) in + Error uu___2 in + FStar_Compiler_Effect.raise uu___1 +let raise_err : 'a . (FStar_Errors_Codes.raw_error * Prims.string) -> 'a = + fun uu___ -> + match uu___ with + | (e, msg) -> + let uu___1 = + let uu___2 = let uu___3 = error_context.get () in (e, msg, uu___3) in + Err uu___2 in + FStar_Compiler_Effect.raise uu___1 + let (log_issue_ctx : FStar_Compiler_Range.range -> (FStar_Errors_Codes.raw_error * Prims.string) -> @@ -633,7 +566,7 @@ let (log_issue_ctx : let i = mk_issue EError (FStar_Pervasives_Native.Some r) msg (FStar_Pervasives_Native.Some errno1) ctx in - let uu___3 = FStar_Options.ide () in + let uu___3 = false in if uu___3 then add_one i else @@ -652,162 +585,3 @@ let (log_issue : match uu___ with | (e, msg) -> let ctx = error_context.get () in log_issue_ctx r (e, msg) ctx -let (add_errors : error Prims.list -> unit) = - fun errs -> - FStar_Compiler_Util.atomically - (fun uu___ -> - FStar_Compiler_List.iter - (fun uu___1 -> - match uu___1 with - | (e, msg, r, ctx) -> log_issue_ctx r (e, msg) ctx) errs) -let (issue_of_exn : Prims.exn -> issue FStar_Pervasives_Native.option) = - fun e -> - match e with - | Error (e1, msg, r, ctx) -> - let errno1 = let uu___ = lookup e1 in error_number uu___ in - FStar_Pervasives_Native.Some - (mk_issue EError (FStar_Pervasives_Native.Some r) msg - (FStar_Pervasives_Native.Some errno1) ctx) - | Err (e1, msg, ctx) -> - let errno1 = let uu___ = lookup e1 in error_number uu___ in - FStar_Pervasives_Native.Some - (mk_issue EError FStar_Pervasives_Native.None msg - (FStar_Pervasives_Native.Some errno1) ctx) - | uu___ -> FStar_Pervasives_Native.None -let (err_exn : Prims.exn -> unit) = - fun exn -> - if exn = Stop - then () - else - (let uu___1 = issue_of_exn exn in - match uu___1 with - | FStar_Pervasives_Native.Some issue1 -> add_one issue1 - | FStar_Pervasives_Native.None -> FStar_Compiler_Effect.raise exn) -let (handleable : Prims.exn -> Prims.bool) = - fun uu___ -> - match uu___ with - | Error uu___1 -> true - | Stop -> true - | Err uu___1 -> true - | uu___1 -> false -let (stop_if_err : unit -> unit) = - fun uu___ -> - let uu___1 = let uu___2 = get_err_count () in uu___2 > Prims.int_zero in - if uu___1 then FStar_Compiler_Effect.raise Stop else () -let raise_error : - 'a . - (FStar_Errors_Codes.raw_error * Prims.string) -> - FStar_Compiler_Range.range -> 'a - = - fun uu___ -> - fun r -> - match uu___ with - | (e, msg) -> - let uu___1 = - let uu___2 = - let uu___3 = error_context.get () in (e, msg, r, uu___3) in - Error uu___2 in - FStar_Compiler_Effect.raise uu___1 -let raise_err : 'a . (FStar_Errors_Codes.raw_error * Prims.string) -> 'a = - fun uu___ -> - match uu___ with - | (e, msg) -> - let uu___1 = - let uu___2 = let uu___3 = error_context.get () in (e, msg, uu___3) in - Err uu___2 in - FStar_Compiler_Effect.raise uu___1 -let with_ctx : 'a . Prims.string -> (unit -> 'a) -> 'a = - fun s -> - fun f -> - error_context.push s; - (let r = - let uu___1 = FStar_Options.trace_error () in - if uu___1 - then let uu___2 = f () in FStar_Pervasives.Inr uu___2 - else - (try - (fun uu___3 -> - match () with - | () -> let uu___4 = f () in FStar_Pervasives.Inr uu___4) () - with - | FStar_Compiler_Effect.Failure msg -> - let uu___4 = - let uu___5 = - let uu___6 = - let uu___7 = error_context.get () in ctx_string uu___7 in - FStar_String.op_Hat msg uu___6 in - FStar_Compiler_Effect.Failure uu___5 in - FStar_Pervasives.Inl uu___4 - | ex -> FStar_Pervasives.Inl ex) in - (let uu___2 = error_context.pop () in ()); - (match r with - | FStar_Pervasives.Inr r1 -> r1 - | FStar_Pervasives.Inl e -> FStar_Compiler_Effect.raise e)) -let with_ctx_if : 'a . Prims.bool -> Prims.string -> (unit -> 'a) -> 'a = - fun b -> fun s -> fun f -> if b then with_ctx s f else f () -let no_ctx : 'a . (unit -> 'a) -> 'a = - fun f -> - let save = error_context.get () in - error_context.clear (); (let res = f () in error_context.set save; res) -let catch_errors : - 'a . (unit -> 'a) -> (issue Prims.list * 'a FStar_Pervasives_Native.option) - = - fun f -> - let newh = mk_default_handler false in - let old = FStar_Compiler_Effect.op_Bang current_handler in - FStar_Compiler_Effect.op_Colon_Equals current_handler newh; - (let r = - try - (fun uu___1 -> - match () with - | () -> let uu___2 = f () in FStar_Pervasives_Native.Some uu___2) - () - with | uu___1 -> (err_exn uu___1; FStar_Pervasives_Native.None) in - let all_issues = newh.eh_report () in - FStar_Compiler_Effect.op_Colon_Equals current_handler old; - (let uu___2 = - FStar_Compiler_List.partition (fun i -> i.issue_level = EError) - all_issues in - match uu___2 with - | (errs, rest) -> - (FStar_Compiler_List.iter old.eh_add_one rest; (errs, r)))) -let (find_multiset_discrepancy : - Prims.int Prims.list -> - Prims.int Prims.list -> - (Prims.int * Prims.int * Prims.int) FStar_Pervasives_Native.option) - = - fun l1 -> - fun l2 -> - let sort = FStar_Compiler_List.sortWith (fun x -> fun y -> x - y) in - let rec collect l = - match l with - | [] -> [] - | hd::tl -> - let uu___ = collect tl in - (match uu___ with - | [] -> [(hd, Prims.int_one)] - | (h, n)::t -> - if h = hd - then (h, (n + Prims.int_one)) :: t - else (hd, Prims.int_one) :: (h, n) :: t) in - let summ l = collect l in - let l11 = let uu___ = sort l1 in summ uu___ in - let l21 = let uu___ = sort l2 in summ uu___ in - let rec aux l12 l22 = - match (l12, l22) with - | ([], []) -> FStar_Pervasives_Native.None - | ((e, n)::uu___, []) -> - FStar_Pervasives_Native.Some (e, n, Prims.int_zero) - | ([], (e, n)::uu___) -> - FStar_Pervasives_Native.Some (e, Prims.int_zero, n) - | ((hd1, n1)::tl1, (hd2, n2)::tl2) -> - if hd1 < hd2 - then FStar_Pervasives_Native.Some (hd1, n1, Prims.int_zero) - else - if hd1 > hd2 - then FStar_Pervasives_Native.Some (hd2, Prims.int_zero, n2) - else - if n1 <> n2 - then FStar_Pervasives_Native.Some (hd1, n1, n2) - else aux tl1 tl2 in - aux l11 l21 \ No newline at end of file diff --git a/engine/backends/fstar/fstar-surface-ast/FStar_Float.ml b/engine/backends/fstar/fstar-surface-ast/FStar_Float.ml deleted file mode 100644 index 39546f959..000000000 --- a/engine/backends/fstar/fstar-surface-ast/FStar_Float.ml +++ /dev/null @@ -1,2 +0,0 @@ -type double = float[@@deriving yojson,show] -type float = double[@@deriving yojson,show] diff --git a/engine/backends/fstar/fstar-surface-ast/FStar_Int16.ml b/engine/backends/fstar/fstar-surface-ast/FStar_Int16.ml deleted file mode 100644 index 2d50e807f..000000000 --- a/engine/backends/fstar/fstar-surface-ast/FStar_Int16.ml +++ /dev/null @@ -1,105 +0,0 @@ -(* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! *) -(* THIS IS AN AUTOGENERATED FILE! See ulib/ml/Makefile *) -(* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! *) - -(* This file is meant to be concatenated to FStar_Ints.ml.body *) -module M = Stdint.Int16 -type int16 = M.t -type t = M.t -let n = Prims.of_int 16 - -let int_to_t x = M.of_string (Z.to_string x) -let __int_to_t = int_to_t -(* This .ml.body file is concatenated to every .ml.prefix file in this - * directory (ulib/ml/) to generate the OCaml realizations for machine - * integers, as they all pretty much share their definitions and are - * based on Stdint. *) - -let v (x:t) : Prims.int = Prims.parse_int (M.to_string x) - -let zero = M.zero -let one = M.one -let ones = M.pred M.zero - -(* Reexport add, plus aliases *) -let add = M.add -let add_underspec = M.add -let add_mod = M.add - -(* Reexport sub, plus aliases *) -let sub = M.sub -let sub_underspec = M.sub -let sub_mod = M.sub - -(* Reexport mul, plus aliases *) -let mul = M.mul -let mul_underspec = M.mul -let mul_mod = M.mul - -(* Conversions to Zarith's int *) -let to_int (x:t) : Z.t = Z.of_string (M.to_string x) -let of_int (x:Z.t) : t = M.of_string (Z.to_string x) - -(* Conversion to native ints; these are potentially unsafe and not part - * of the interface: they are meant to be called only from OCaml code - * that is doing the right thing *) -let of_native_int (x:int) : t = M.of_int x -let to_native_int (x:t) : int = M.to_int x - -(* Just reexport these *) -let div = M.div -let rem = M.rem -let logand = M.logand -let logxor = M.logxor -let logor = M.logor -let lognot = M.lognot -let to_string = M.to_string -let of_string = M.of_string - -let to_string_hex = M.to_string_hex - -let to_string_hex_pad i = - let s0 = M.to_string_hex i in - let len = (String.length s0 - 2) in - let s1 = String.sub s0 2 len in (* Remove leading "0x" *) - let zeroes = String.make ((Z.to_int n / 4) - len) '0' in - zeroes ^ s1 - -(* The shifts take a uint32 argument, so we need to convert *) -let shift_right n i = M.shift_right n (Stdint.Uint32.to_int i) -let shift_left n i = M.shift_left n (Stdint.Uint32.to_int i) -let shift_arithmetic_right = shift_right - -(* Comparison operators *) -let eq (a:t) (b:t) : bool = a = b -let gt (a:t) (b:t) : bool = a > b -let gte (a:t) (b:t) : bool = a >= b -let lt (a:t) (b:t) : bool = a < b -let lte (a:t) (b:t) : bool = a <= b - -(* NOT Constant time operators *) -let eq_mask (a:t) (b:t) : t = if a = b then ones else zero -let gte_mask (a:t) (b:t) : t = if a >= b then ones else zero - -(* Infix notations *) -let op_Plus_Hat = add -let op_Plus_Question_Hat = add_underspec -let op_Plus_Percent_Hat = add_mod -let op_Subtraction_Hat = sub -let op_Subtraction_Question_Hat = sub_underspec -let op_Subtraction_Percent_Hat = sub_mod -let op_Star_Hat = mul -let op_Star_Question_Hat = mul_underspec -let op_Star_Percent_Hat = mul_mod -let op_Slash_Hat = div -let op_Percent_Hat = rem -let op_Hat_Hat = logxor -let op_Amp_Hat = logand -let op_Bar_Hat = logor -let op_Less_Less_Hat = shift_left -let op_Greater_Greater_Hat = shift_right -let op_Equals_Hat = eq -let op_Greater_Hat = gt -let op_Greater_Equals_Hat = gte -let op_Less_Hat = lt -let op_Less_Equals_Hat = lte diff --git a/engine/backends/fstar/fstar-surface-ast/FStar_Int32.ml b/engine/backends/fstar/fstar-surface-ast/FStar_Int32.ml deleted file mode 100644 index 07bfb0ee7..000000000 --- a/engine/backends/fstar/fstar-surface-ast/FStar_Int32.ml +++ /dev/null @@ -1,104 +0,0 @@ -(* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! *) -(* THIS IS AN AUTOGENERATED FILE! See ulib/ml/Makefile *) -(* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! *) - -module M = Stdint.Int32 -type int32 = M.t -type t = M.t -let n = Prims.of_int 32 - -let int_to_t x = M.of_string (Z.to_string x) -let __int_to_t = int_to_t -(* This .ml.body file is concatenated to every .ml.prefix file in this - * directory (ulib/ml/) to generate the OCaml realizations for machine - * integers, as they all pretty much share their definitions and are - * based on Stdint. *) - -let v (x:t) : Prims.int = Prims.parse_int (M.to_string x) - -let zero = M.zero -let one = M.one -let ones = M.pred M.zero - -(* Reexport add, plus aliases *) -let add = M.add -let add_underspec = M.add -let add_mod = M.add - -(* Reexport sub, plus aliases *) -let sub = M.sub -let sub_underspec = M.sub -let sub_mod = M.sub - -(* Reexport mul, plus aliases *) -let mul = M.mul -let mul_underspec = M.mul -let mul_mod = M.mul - -(* Conversions to Zarith's int *) -let to_int (x:t) : Z.t = Z.of_string (M.to_string x) -let of_int (x:Z.t) : t = M.of_string (Z.to_string x) - -(* Conversion to native ints; these are potentially unsafe and not part - * of the interface: they are meant to be called only from OCaml code - * that is doing the right thing *) -let of_native_int (x:int) : t = M.of_int x -let to_native_int (x:t) : int = M.to_int x - -(* Just reexport these *) -let div = M.div -let rem = M.rem -let logand = M.logand -let logxor = M.logxor -let logor = M.logor -let lognot = M.lognot -let to_string = M.to_string -let of_string = M.of_string - -let to_string_hex = M.to_string_hex - -let to_string_hex_pad i = - let s0 = M.to_string_hex i in - let len = (String.length s0 - 2) in - let s1 = String.sub s0 2 len in (* Remove leading "0x" *) - let zeroes = String.make ((Z.to_int n / 4) - len) '0' in - zeroes ^ s1 - -(* The shifts take a uint32 argument, so we need to convert *) -let shift_right n i = M.shift_right n (Stdint.Uint32.to_int i) -let shift_left n i = M.shift_left n (Stdint.Uint32.to_int i) -let shift_arithmetic_right = shift_right - -(* Comparison operators *) -let eq (a:t) (b:t) : bool = a = b -let gt (a:t) (b:t) : bool = a > b -let gte (a:t) (b:t) : bool = a >= b -let lt (a:t) (b:t) : bool = a < b -let lte (a:t) (b:t) : bool = a <= b - -(* NOT Constant time operators *) -let eq_mask (a:t) (b:t) : t = if a = b then ones else zero -let gte_mask (a:t) (b:t) : t = if a >= b then ones else zero - -(* Infix notations *) -let op_Plus_Hat = add -let op_Plus_Question_Hat = add_underspec -let op_Plus_Percent_Hat = add_mod -let op_Subtraction_Hat = sub -let op_Subtraction_Question_Hat = sub_underspec -let op_Subtraction_Percent_Hat = sub_mod -let op_Star_Hat = mul -let op_Star_Question_Hat = mul_underspec -let op_Star_Percent_Hat = mul_mod -let op_Slash_Hat = div -let op_Percent_Hat = rem -let op_Hat_Hat = logxor -let op_Amp_Hat = logand -let op_Bar_Hat = logor -let op_Less_Less_Hat = shift_left -let op_Greater_Greater_Hat = shift_right -let op_Equals_Hat = eq -let op_Greater_Hat = gt -let op_Greater_Equals_Hat = gte -let op_Less_Hat = lt -let op_Less_Equals_Hat = lte diff --git a/engine/backends/fstar/fstar-surface-ast/FStar_Int64.ml b/engine/backends/fstar/fstar-surface-ast/FStar_Int64.ml deleted file mode 100644 index 33d2e0082..000000000 --- a/engine/backends/fstar/fstar-surface-ast/FStar_Int64.ml +++ /dev/null @@ -1,105 +0,0 @@ -(* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! *) -(* THIS IS AN AUTOGENERATED FILE! See ulib/ml/Makefile *) -(* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! *) - -(* This file is meant to be concatenated to FStar_Ints.ml.body *) -module M = Stdint.Int64 -type int64 = M.t -type t = M.t -let n = Prims.of_int 64 - -let int_to_t x = M.of_string (Z.to_string x) -let __int_to_t = int_to_t -(* This .ml.body file is concatenated to every .ml.prefix file in this - * directory (ulib/ml/) to generate the OCaml realizations for machine - * integers, as they all pretty much share their definitions and are - * based on Stdint. *) - -let v (x:t) : Prims.int = Prims.parse_int (M.to_string x) - -let zero = M.zero -let one = M.one -let ones = M.pred M.zero - -(* Reexport add, plus aliases *) -let add = M.add -let add_underspec = M.add -let add_mod = M.add - -(* Reexport sub, plus aliases *) -let sub = M.sub -let sub_underspec = M.sub -let sub_mod = M.sub - -(* Reexport mul, plus aliases *) -let mul = M.mul -let mul_underspec = M.mul -let mul_mod = M.mul - -(* Conversions to Zarith's int *) -let to_int (x:t) : Z.t = Z.of_string (M.to_string x) -let of_int (x:Z.t) : t = M.of_string (Z.to_string x) - -(* Conversion to native ints; these are potentially unsafe and not part - * of the interface: they are meant to be called only from OCaml code - * that is doing the right thing *) -let of_native_int (x:int) : t = M.of_int x -let to_native_int (x:t) : int = M.to_int x - -(* Just reexport these *) -let div = M.div -let rem = M.rem -let logand = M.logand -let logxor = M.logxor -let logor = M.logor -let lognot = M.lognot -let to_string = M.to_string -let of_string = M.of_string - -let to_string_hex = M.to_string_hex - -let to_string_hex_pad i = - let s0 = M.to_string_hex i in - let len = (String.length s0 - 2) in - let s1 = String.sub s0 2 len in (* Remove leading "0x" *) - let zeroes = String.make ((Z.to_int n / 4) - len) '0' in - zeroes ^ s1 - -(* The shifts take a uint32 argument, so we need to convert *) -let shift_right n i = M.shift_right n (Stdint.Uint32.to_int i) -let shift_left n i = M.shift_left n (Stdint.Uint32.to_int i) -let shift_arithmetic_right = shift_right - -(* Comparison operators *) -let eq (a:t) (b:t) : bool = a = b -let gt (a:t) (b:t) : bool = a > b -let gte (a:t) (b:t) : bool = a >= b -let lt (a:t) (b:t) : bool = a < b -let lte (a:t) (b:t) : bool = a <= b - -(* NOT Constant time operators *) -let eq_mask (a:t) (b:t) : t = if a = b then ones else zero -let gte_mask (a:t) (b:t) : t = if a >= b then ones else zero - -(* Infix notations *) -let op_Plus_Hat = add -let op_Plus_Question_Hat = add_underspec -let op_Plus_Percent_Hat = add_mod -let op_Subtraction_Hat = sub -let op_Subtraction_Question_Hat = sub_underspec -let op_Subtraction_Percent_Hat = sub_mod -let op_Star_Hat = mul -let op_Star_Question_Hat = mul_underspec -let op_Star_Percent_Hat = mul_mod -let op_Slash_Hat = div -let op_Percent_Hat = rem -let op_Hat_Hat = logxor -let op_Amp_Hat = logand -let op_Bar_Hat = logor -let op_Less_Less_Hat = shift_left -let op_Greater_Greater_Hat = shift_right -let op_Equals_Hat = eq -let op_Greater_Hat = gt -let op_Greater_Equals_Hat = gte -let op_Less_Hat = lt -let op_Less_Equals_Hat = lte diff --git a/engine/backends/fstar/fstar-surface-ast/FStar_Int8.ml b/engine/backends/fstar/fstar-surface-ast/FStar_Int8.ml deleted file mode 100644 index 5b0ca3d51..000000000 --- a/engine/backends/fstar/fstar-surface-ast/FStar_Int8.ml +++ /dev/null @@ -1,105 +0,0 @@ -(* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! *) -(* THIS IS AN AUTOGENERATED FILE! See ulib/ml/Makefile *) -(* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! *) - -(* This file is meant to be concatenated to FStar_Ints.ml.body *) -module M = Stdint.Int8 -type int8 = M.t -type t = M.t -let n = Prims.of_int 8 - -let int_to_t x = M.of_string (Z.to_string x) -let __int_to_t = int_to_t -(* This .ml.body file is concatenated to every .ml.prefix file in this - * directory (ulib/ml/) to generate the OCaml realizations for machine - * integers, as they all pretty much share their definitions and are - * based on Stdint. *) - -let v (x:t) : Prims.int = Prims.parse_int (M.to_string x) - -let zero = M.zero -let one = M.one -let ones = M.pred M.zero - -(* Reexport add, plus aliases *) -let add = M.add -let add_underspec = M.add -let add_mod = M.add - -(* Reexport sub, plus aliases *) -let sub = M.sub -let sub_underspec = M.sub -let sub_mod = M.sub - -(* Reexport mul, plus aliases *) -let mul = M.mul -let mul_underspec = M.mul -let mul_mod = M.mul - -(* Conversions to Zarith's int *) -let to_int (x:t) : Z.t = Z.of_string (M.to_string x) -let of_int (x:Z.t) : t = M.of_string (Z.to_string x) - -(* Conversion to native ints; these are potentially unsafe and not part - * of the interface: they are meant to be called only from OCaml code - * that is doing the right thing *) -let of_native_int (x:int) : t = M.of_int x -let to_native_int (x:t) : int = M.to_int x - -(* Just reexport these *) -let div = M.div -let rem = M.rem -let logand = M.logand -let logxor = M.logxor -let logor = M.logor -let lognot = M.lognot -let to_string = M.to_string -let of_string = M.of_string - -let to_string_hex = M.to_string_hex - -let to_string_hex_pad i = - let s0 = M.to_string_hex i in - let len = (String.length s0 - 2) in - let s1 = String.sub s0 2 len in (* Remove leading "0x" *) - let zeroes = String.make ((Z.to_int n / 4) - len) '0' in - zeroes ^ s1 - -(* The shifts take a uint32 argument, so we need to convert *) -let shift_right n i = M.shift_right n (Stdint.Uint32.to_int i) -let shift_left n i = M.shift_left n (Stdint.Uint32.to_int i) -let shift_arithmetic_right = shift_right - -(* Comparison operators *) -let eq (a:t) (b:t) : bool = a = b -let gt (a:t) (b:t) : bool = a > b -let gte (a:t) (b:t) : bool = a >= b -let lt (a:t) (b:t) : bool = a < b -let lte (a:t) (b:t) : bool = a <= b - -(* NOT Constant time operators *) -let eq_mask (a:t) (b:t) : t = if a = b then ones else zero -let gte_mask (a:t) (b:t) : t = if a >= b then ones else zero - -(* Infix notations *) -let op_Plus_Hat = add -let op_Plus_Question_Hat = add_underspec -let op_Plus_Percent_Hat = add_mod -let op_Subtraction_Hat = sub -let op_Subtraction_Question_Hat = sub_underspec -let op_Subtraction_Percent_Hat = sub_mod -let op_Star_Hat = mul -let op_Star_Question_Hat = mul_underspec -let op_Star_Percent_Hat = mul_mod -let op_Slash_Hat = div -let op_Percent_Hat = rem -let op_Hat_Hat = logxor -let op_Amp_Hat = logand -let op_Bar_Hat = logor -let op_Less_Less_Hat = shift_left -let op_Greater_Greater_Hat = shift_right -let op_Equals_Hat = eq -let op_Greater_Hat = gt -let op_Greater_Equals_Hat = gte -let op_Less_Hat = lt -let op_Less_Equals_Hat = lte diff --git a/engine/backends/fstar/fstar-surface-ast/FStar_List.ml b/engine/backends/fstar/fstar-surface-ast/FStar_List.ml index d1b052be0..9e35917fe 100644 --- a/engine/backends/fstar/fstar-surface-ast/FStar_List.ml +++ b/engine/backends/fstar/fstar-surface-ast/FStar_List.ml @@ -1,79 +1,39 @@ (* We give an implementation here using OCaml's BatList, which provides tail-recursive versions of most functions *) -include FStar_List_Tot_Base - let isEmpty l = l = [] -let singleton x = [x] -let mem = BatList.mem -let memT = mem let hd = BatList.hd -let tl = BatList.tl let tail = BatList.tl +let tl = BatList.tl -let nth l i = BatList.nth l (Z.to_int i) +let rec last = function + | x :: [] -> x + | _ :: tl -> last tl let length l = Z.of_int (BatList.length l) let rev = BatList.rev +let append = BatList.append +let op_At = append +let flatten = BatList.flatten let map = BatList.map -let mapT = map let mapi f l = BatList.mapi (fun i x -> f (Z.of_int i) x) l -let map2 = BatList.map2 -let rec map3 f l1 l2 l3 = - match l1, l2, l3 with - | [], [], [] -> [] - | x::xs, y::ys, z::zs -> (f x y z)::(map3 f xs ys zs) - | _, _, _ -> failwith "The lists do not have the same length" -let iter = BatList.iter -let iter2 = BatList.iter2 -let iteri_aux _ _ _ = failwith "FStar_List.ml: Not implemented: iteri_aux" -let iteri f l = BatList.iteri (fun i x -> f (Z.of_int i) x) l -let partition = BatList.partition -let append = BatList.append -let rev_append = BatList.rev_append let fold_left = BatList.fold_left let fold_right = BatList.fold_right let fold_left2 = BatList.fold_left2 -let fold_right2 = BatList.fold_right2 -let rev_map_onto f l acc = fold_left (fun acc x -> f x :: acc) acc l -let rec init = function - | [] -> failwith "init: empty list" - | [h] -> [] - | h::t -> h::(init t) -let last = BatList.last -let last_opt l = List.fold_left (fun _ x -> Some x) None l -let collect f l = BatList.flatten (BatList.map f l) -let unzip = BatList.split -let rec unzip3 = function - | [] -> ([],[],[]) - | (x,y,z)::xyzs -> - let (xs,ys,zs) = unzip3 xyzs in - (x::xs,y::ys,z::zs) +let existsb f l = BatList.exists f l +let find f l = try Some (BatList.find f l) with | Not_found -> None let filter = BatList.filter -let sortWith f l = BatList.sort (fun x y -> Z.to_int (f x y)) l let for_all = BatList.for_all -let forall2 = BatList.for_all2 -let tryFind f l = try Some (BatList.find f l) with | Not_found -> None -let tryFindT = tryFind -let find = tryFind -let tryPick f l = try f (BatList.find (fun x -> f x <> None) l) with | Not_found -> None -let flatten = BatList.flatten -let concat = flatten -let split = unzip +let collect f l = BatList.flatten (BatList.map f l) +let tryFind = find let choose = BatList.filter_map -let existsb f l = BatList.exists f l -let existsML f l = BatList.exists f l -let contains x l = BatList.exists (fun y -> x = y) l -let zip = BatList.combine -let splitAt x l = BatList.split_at (Z.to_int x) l -let filter_map = BatList.filter_map -let index f l = - Z.of_int (fst (BatList.findi (fun _ x -> f x) l)) - -let rec zip3 l1 l2 l3 = - match l1, l2, l3 with - | [], [], [] -> [] - | h1::t1, h2::t2, h3::t3 -> (h1, h2, h3) :: (zip3 t1 t2 t3) - | _ -> failwith "zip3" -let unique = BatList.unique -let map_flatten f l = flatten (map f l) +let partition = BatList.partition +let sortWith f l = BatList.sort (fun x y -> Z.to_int (f x y)) l -let span = BatList.span +let isEmpty l = l = [] +let singleton x = [x] +let mem = BatList.mem +let memT = mem +let hd = BatList.hd +let tl = BatList.tl +let tail = BatList.tl +let iter = BatList.iter +let forall2 = BatList.for_all2 diff --git a/engine/backends/fstar/fstar-surface-ast/FStar_List_Tot_Base.ml b/engine/backends/fstar/fstar-surface-ast/FStar_List_Tot_Base.ml deleted file mode 100644 index 537c03abb..000000000 --- a/engine/backends/fstar/fstar-surface-ast/FStar_List_Tot_Base.ml +++ /dev/null @@ -1,76 +0,0 @@ -(* We give an implementation here using OCaml's BatList, - which provide tail-recursive versions of most functions. - The rest we implement manually. *) - -let isEmpty l = l = [] -let hd = BatList.hd -let tail = BatList.tl -let tl = BatList.tl - -let rec last = function - | x :: [] -> x - | _ :: tl -> last tl - -let rec init = function - | _ :: [] -> [] - | hd :: tl -> hd :: init tl - -let length l = Z.of_int (BatList.length l) -let nth l i = try Some (BatList.nth l (Z.to_int i)) with _ -> None -let index l i = BatList.nth l (Z.to_int i) - -let rec count x = function - | [] -> Prims.int_zero - | hd::tl -> if x=hd then Z.add Prims.int_one (count x tl) else count x tl - -let rev_acc l r = BatList.rev_append l r -let rev = BatList.rev -let append = BatList.append -let op_At = append -let snoc (x, y) = append x [y] -let flatten = BatList.flatten -let map = BatList.map -let mapi_init _ _ _ = failwith "FStar_List_Tot_Base.ml: Not implemented: mapi_init" -let mapi f l = BatList.mapi (fun i x -> f (Z.of_int i) x) l -let concatMap f l = flatten (map f l) -let fold_left = BatList.fold_left -let fold_right = BatList.fold_right -let fold_left2 = BatList.fold_left2 -let mem = BatList.mem -type ('a, 'b, 'c) memP = unit -let contains x l = BatList.exists (fun y -> x = y) l -let existsb f l = BatList.exists f l -let find f l = try Some (BatList.find f l) with | Not_found -> None -let filter = BatList.filter -let for_all = BatList.for_all -let collect f l = BatList.flatten (BatList.map f l) -let tryFind = find -let tryPick f l = try f (BatList.find (fun x -> f x <> None) l) with | Not_found -> None -let choose = BatList.filter_map -let partition = BatList.partition -let subset la lb = BatList.subset (fun x y -> if x = y then 0 else 1) la lb - -let rec noRepeats = function - | [] -> true - | h :: tl -> not (mem h tl) && noRepeats tl - -let assoc x l = match List.assoc x l with exception Not_found -> None | x -> Some x -let split = BatList.split -let unzip = split -let rec unzip3 = function - | [] -> ([],[],[]) - | (x,y,z)::xyzs -> - let (xs,ys,zs) = unzip3 xyzs in - (x::xs,y::ys,z::zs) - -let splitAt n l = BatList.split_at (Z.to_int n) l -let unsnoc l = let l1, l2 = splitAt (Z.sub (length l) Z.one) l in l1, hd l2 -let split3 l i = let a, a1 = splitAt i l in let b :: c = a1 in a, b, c - -let bool_of_compare f x y = Z.gt (f x y) Z.zero -let compare_of_bool = - fun rel -> fun x -> fun y -> if (rel x y) then Z.one else (if x = y then Z.zero else (Z.neg Z.one)) -let sortWith f l = BatList.sort (fun x y -> Z.to_int (f x y)) l -let list_unref l = l -let list_ref _ l = l -let list_refb _ l = l diff --git a/engine/backends/fstar/fstar-surface-ast/FStar_Monotonic_Heap.ml b/engine/backends/fstar/fstar-surface-ast/FStar_Monotonic_Heap.ml deleted file mode 100644 index 1c1cc85cb..000000000 --- a/engine/backends/fstar/fstar-surface-ast/FStar_Monotonic_Heap.ml +++ /dev/null @@ -1,36 +0,0 @@ -type heap = unit - -type nonrec 'a ref = 'a ref - -type ('a, 'b) mref = 'a ref - -let emp = - () - -(* Logical functions on heap *) -(* TODO : complete the functions to have the same interface as in FStar.Heap.fsti *) - -let addr_of _ = Obj.magic () -let is_mm _ = Obj.magic () - -(* let compare_addrs *) - -type ('a, 'b, 'c, 'd) contains -type ('a, 'b) addr_unused_in -type ('a, 'b, 'c, 'd) unused_in -let fresh _ _ _ = Obj.magic () - -let sel _ _ = Obj.magic () -let upd _ _ _ = Obj.magic () -let alloc _ _ _ = Obj.magic () - -let free_mm _ _ = Obj.magic () -let sel_tot = sel -let upd_tot = upd - -(* Untyped view of references *) -type aref = - | Ref of (unit * unit) -let dummy_aref = Ref ((), ()) -let aref_of _ = dummy_aref -let ref_of _ _ = Obj.magic () diff --git a/engine/backends/fstar/fstar-surface-ast/FStar_Options.ml b/engine/backends/fstar/fstar-surface-ast/FStar_Options.ml deleted file mode 100644 index e209731c2..000000000 --- a/engine/backends/fstar/fstar-surface-ast/FStar_Options.ml +++ /dev/null @@ -1,2511 +0,0 @@ -open Prims -type debug_level_t = - | Low - | Medium - | High - | Extreme - | Other of Prims.string -let (uu___is_Low : debug_level_t -> Prims.bool) = - fun projectee -> match projectee with | Low -> true | uu___ -> false -let (uu___is_Medium : debug_level_t -> Prims.bool) = - fun projectee -> match projectee with | Medium -> true | uu___ -> false -let (uu___is_High : debug_level_t -> Prims.bool) = - fun projectee -> match projectee with | High -> true | uu___ -> false -let (uu___is_Extreme : debug_level_t -> Prims.bool) = - fun projectee -> match projectee with | Extreme -> true | uu___ -> false -let (uu___is_Other : debug_level_t -> Prims.bool) = - fun projectee -> match projectee with | Other _0 -> true | uu___ -> false -let (__proj__Other__item___0 : debug_level_t -> Prims.string) = - fun projectee -> match projectee with | Other _0 -> _0 -type option_val = - | Bool of Prims.bool - | String of Prims.string - | Path of Prims.string - | Int of Prims.int - | List of option_val Prims.list - | Unset -let (uu___is_Bool : option_val -> Prims.bool) = - fun projectee -> match projectee with | Bool _0 -> true | uu___ -> false -let (__proj__Bool__item___0 : option_val -> Prims.bool) = - fun projectee -> match projectee with | Bool _0 -> _0 -let (uu___is_String : option_val -> Prims.bool) = - fun projectee -> match projectee with | String _0 -> true | uu___ -> false -let (__proj__String__item___0 : option_val -> Prims.string) = - fun projectee -> match projectee with | String _0 -> _0 -let (uu___is_Path : option_val -> Prims.bool) = - fun projectee -> match projectee with | Path _0 -> true | uu___ -> false -let (__proj__Path__item___0 : option_val -> Prims.string) = - fun projectee -> match projectee with | Path _0 -> _0 -let (uu___is_Int : option_val -> Prims.bool) = - fun projectee -> match projectee with | Int _0 -> true | uu___ -> false -let (__proj__Int__item___0 : option_val -> Prims.int) = - fun projectee -> match projectee with | Int _0 -> _0 -let (uu___is_List : option_val -> Prims.bool) = - fun projectee -> match projectee with | List _0 -> true | uu___ -> false -let (__proj__List__item___0 : option_val -> option_val Prims.list) = - fun projectee -> match projectee with | List _0 -> _0 -let (uu___is_Unset : option_val -> Prims.bool) = - fun projectee -> match projectee with | Unset -> true | uu___ -> false -type optionstate = option_val FStar_Compiler_Util.smap -type opt_type = - | Const of option_val - | IntStr of Prims.string - | BoolStr - | PathStr of Prims.string - | SimpleStr of Prims.string - | EnumStr of Prims.string Prims.list - | OpenEnumStr of (Prims.string Prims.list * Prims.string) - | PostProcessed of ((option_val -> option_val) * opt_type) - | Accumulated of opt_type - | ReverseAccumulated of opt_type - | WithSideEffect of ((unit -> unit) * opt_type) -let (uu___is_Const : opt_type -> Prims.bool) = - fun projectee -> match projectee with | Const _0 -> true | uu___ -> false -let (__proj__Const__item___0 : opt_type -> option_val) = - fun projectee -> match projectee with | Const _0 -> _0 -let (uu___is_IntStr : opt_type -> Prims.bool) = - fun projectee -> match projectee with | IntStr _0 -> true | uu___ -> false -let (__proj__IntStr__item___0 : opt_type -> Prims.string) = - fun projectee -> match projectee with | IntStr _0 -> _0 -let (uu___is_BoolStr : opt_type -> Prims.bool) = - fun projectee -> match projectee with | BoolStr -> true | uu___ -> false -let (uu___is_PathStr : opt_type -> Prims.bool) = - fun projectee -> match projectee with | PathStr _0 -> true | uu___ -> false -let (__proj__PathStr__item___0 : opt_type -> Prims.string) = - fun projectee -> match projectee with | PathStr _0 -> _0 -let (uu___is_SimpleStr : opt_type -> Prims.bool) = - fun projectee -> - match projectee with | SimpleStr _0 -> true | uu___ -> false -let (__proj__SimpleStr__item___0 : opt_type -> Prims.string) = - fun projectee -> match projectee with | SimpleStr _0 -> _0 -let (uu___is_EnumStr : opt_type -> Prims.bool) = - fun projectee -> match projectee with | EnumStr _0 -> true | uu___ -> false -let (__proj__EnumStr__item___0 : opt_type -> Prims.string Prims.list) = - fun projectee -> match projectee with | EnumStr _0 -> _0 -let (uu___is_OpenEnumStr : opt_type -> Prims.bool) = - fun projectee -> - match projectee with | OpenEnumStr _0 -> true | uu___ -> false -let (__proj__OpenEnumStr__item___0 : - opt_type -> (Prims.string Prims.list * Prims.string)) = - fun projectee -> match projectee with | OpenEnumStr _0 -> _0 -let (uu___is_PostProcessed : opt_type -> Prims.bool) = - fun projectee -> - match projectee with | PostProcessed _0 -> true | uu___ -> false -let (__proj__PostProcessed__item___0 : - opt_type -> ((option_val -> option_val) * opt_type)) = - fun projectee -> match projectee with | PostProcessed _0 -> _0 -let (uu___is_Accumulated : opt_type -> Prims.bool) = - fun projectee -> - match projectee with | Accumulated _0 -> true | uu___ -> false -let (__proj__Accumulated__item___0 : opt_type -> opt_type) = - fun projectee -> match projectee with | Accumulated _0 -> _0 -let (uu___is_ReverseAccumulated : opt_type -> Prims.bool) = - fun projectee -> - match projectee with | ReverseAccumulated _0 -> true | uu___ -> false -let (__proj__ReverseAccumulated__item___0 : opt_type -> opt_type) = - fun projectee -> match projectee with | ReverseAccumulated _0 -> _0 -let (uu___is_WithSideEffect : opt_type -> Prims.bool) = - fun projectee -> - match projectee with | WithSideEffect _0 -> true | uu___ -> false -let (__proj__WithSideEffect__item___0 : - opt_type -> ((unit -> unit) * opt_type)) = - fun projectee -> match projectee with | WithSideEffect _0 -> _0 -let (debug_embedding : Prims.bool FStar_Compiler_Effect.ref) = - FStar_Compiler_Util.mk_ref false -let (eager_embedding : Prims.bool FStar_Compiler_Effect.ref) = - FStar_Compiler_Util.mk_ref false -let (__unit_tests__ : Prims.bool FStar_Compiler_Effect.ref) = - FStar_Compiler_Util.mk_ref false -let (__unit_tests : unit -> Prims.bool) = - fun uu___ -> FStar_Compiler_Effect.op_Bang __unit_tests__ -let (__set_unit_tests : unit -> unit) = - fun uu___ -> FStar_Compiler_Effect.op_Colon_Equals __unit_tests__ true -let (__clear_unit_tests : unit -> unit) = - fun uu___ -> FStar_Compiler_Effect.op_Colon_Equals __unit_tests__ false -let (as_bool : option_val -> Prims.bool) = - fun uu___ -> - match uu___ with - | Bool b -> b - | uu___1 -> failwith "Impos: expected Bool" -let (as_int : option_val -> Prims.int) = - fun uu___ -> - match uu___ with | Int b -> b | uu___1 -> failwith "Impos: expected Int" -let (as_string : option_val -> Prims.string) = - fun uu___ -> - match uu___ with - | String b -> b - | Path b -> FStar_Common.try_convert_file_name_to_mixed b - | uu___1 -> failwith "Impos: expected String" -let (as_list' : option_val -> option_val Prims.list) = - fun uu___ -> - match uu___ with - | List ts -> ts - | uu___1 -> failwith "Impos: expected List" -let as_list : - 'uuuuu . (option_val -> 'uuuuu) -> option_val -> 'uuuuu Prims.list = - fun as_t -> - fun x -> - let uu___ = as_list' x in - FStar_Compiler_Effect.op_Bar_Greater uu___ - (FStar_Compiler_List.map as_t) -let as_option : - 'uuuuu . - (option_val -> 'uuuuu) -> - option_val -> 'uuuuu FStar_Pervasives_Native.option - = - fun as_t -> - fun uu___ -> - match uu___ with - | Unset -> FStar_Pervasives_Native.None - | v -> let uu___1 = as_t v in FStar_Pervasives_Native.Some uu___1 -let (as_comma_string_list : option_val -> Prims.string Prims.list) = - fun uu___ -> - match uu___ with - | List ls -> - let uu___1 = - FStar_Compiler_List.map - (fun l -> - let uu___2 = as_string l in - FStar_Compiler_Util.split uu___2 ",") ls in - FStar_Compiler_Effect.op_Less_Bar FStar_Compiler_List.flatten uu___1 - | uu___1 -> failwith "Impos: expected String (comma list)" -let copy_optionstate : - 'uuuuu . 'uuuuu FStar_Compiler_Util.smap -> 'uuuuu FStar_Compiler_Util.smap - = fun m -> FStar_Compiler_Util.smap_copy m -let (fstar_options : - optionstate Prims.list Prims.list FStar_Compiler_Effect.ref) = - FStar_Compiler_Util.mk_ref [] -let (internal_peek : unit -> optionstate) = - fun uu___ -> - let uu___1 = - let uu___2 = FStar_Compiler_Effect.op_Bang fstar_options in - FStar_Compiler_List.hd uu___2 in - FStar_Compiler_List.hd uu___1 -let (peek : unit -> optionstate) = - fun uu___ -> let uu___1 = internal_peek () in copy_optionstate uu___1 -let (pop : unit -> unit) = - fun uu___ -> - let uu___1 = FStar_Compiler_Effect.op_Bang fstar_options in - match uu___1 with - | [] -> failwith "TOO MANY POPS!" - | uu___2::[] -> failwith "TOO MANY POPS!" - | uu___2::tl -> FStar_Compiler_Effect.op_Colon_Equals fstar_options tl -let (push : unit -> unit) = - fun uu___ -> - let uu___1 = - let uu___2 = - let uu___3 = - let uu___4 = FStar_Compiler_Effect.op_Bang fstar_options in - FStar_Compiler_List.hd uu___4 in - FStar_Compiler_List.map copy_optionstate uu___3 in - let uu___3 = FStar_Compiler_Effect.op_Bang fstar_options in uu___2 :: - uu___3 in - FStar_Compiler_Effect.op_Colon_Equals fstar_options uu___1 -let (internal_pop : unit -> Prims.bool) = - fun uu___ -> - let curstack = - let uu___1 = FStar_Compiler_Effect.op_Bang fstar_options in - FStar_Compiler_List.hd uu___1 in - match curstack with - | [] -> failwith "impossible: empty current option stack" - | uu___1::[] -> false - | uu___1::tl -> - ((let uu___3 = - let uu___4 = - let uu___5 = FStar_Compiler_Effect.op_Bang fstar_options in - FStar_Compiler_List.tl uu___5 in - tl :: uu___4 in - FStar_Compiler_Effect.op_Colon_Equals fstar_options uu___3); - true) -let (internal_push : unit -> unit) = - fun uu___ -> - let curstack = - let uu___1 = FStar_Compiler_Effect.op_Bang fstar_options in - FStar_Compiler_List.hd uu___1 in - let stack' = - let uu___1 = - let uu___2 = FStar_Compiler_List.hd curstack in - copy_optionstate uu___2 in - uu___1 :: curstack in - let uu___1 = - let uu___2 = - let uu___3 = FStar_Compiler_Effect.op_Bang fstar_options in - FStar_Compiler_List.tl uu___3 in - stack' :: uu___2 in - FStar_Compiler_Effect.op_Colon_Equals fstar_options uu___1 -let (set : optionstate -> unit) = - fun o -> - let uu___ = FStar_Compiler_Effect.op_Bang fstar_options in - match uu___ with - | [] -> failwith "set on empty option stack" - | []::uu___1 -> failwith "set on empty current option stack" - | (uu___1::tl)::os -> - FStar_Compiler_Effect.op_Colon_Equals fstar_options ((o :: tl) :: os) -let (snapshot : unit -> (Prims.int * unit)) = - fun uu___ -> FStar_Common.snapshot push fstar_options () -let (rollback : Prims.int FStar_Pervasives_Native.option -> unit) = - fun depth -> FStar_Common.rollback pop fstar_options depth -let (set_option : Prims.string -> option_val -> unit) = - fun k -> - fun v -> - let map = internal_peek () in - if k = "report_assumes" - then - let uu___ = FStar_Compiler_Util.smap_try_find map k in - match uu___ with - | FStar_Pervasives_Native.Some (String "error") -> () - | uu___1 -> FStar_Compiler_Util.smap_add map k v - else FStar_Compiler_Util.smap_add map k v -let (set_option' : (Prims.string * option_val) -> unit) = - fun uu___ -> match uu___ with | (k, v) -> set_option k v -let (set_admit_smt_queries : Prims.bool -> unit) = - fun b -> set_option "admit_smt_queries" (Bool b) -let (defaults : (Prims.string * option_val) Prims.list) = - [("__temp_fast_implicits", (Bool false)); - ("abort_on", (Int Prims.int_zero)); - ("admit_smt_queries", (Bool false)); - ("admit_except", Unset); - ("disallow_unification_guards", (Bool false)); - ("already_cached", Unset); - ("cache_checked_modules", (Bool false)); - ("cache_dir", Unset); - ("cache_off", (Bool false)); - ("compat_pre_core", Unset); - ("compat_pre_typed_indexed_effects", (Bool false)); - ("print_cache_version", (Bool false)); - ("cmi", (Bool false)); - ("codegen", Unset); - ("codegen-lib", (List [])); - ("debug", (List [])); - ("debug_level", (List [])); - ("defensive", (String "no")); - ("dep", Unset); - ("detail_errors", (Bool false)); - ("detail_hint_replay", (Bool false)); - ("dump_module", (List [])); - ("eager_subtyping", (Bool false)); - ("error_contexts", (Bool false)); - ("expose_interfaces", (Bool false)); - ("extract", Unset); - ("extract_all", (Bool false)); - ("extract_module", (List [])); - ("extract_namespace", (List [])); - ("full_context_dependency", (Bool true)); - ("hide_uvar_nums", (Bool false)); - ("hint_info", (Bool false)); - ("hint_dir", Unset); - ("hint_file", Unset); - ("in", (Bool false)); - ("ide", (Bool false)); - ("ide_id_info_off", (Bool false)); - ("lsp", (Bool false)); - ("include", (List [])); - ("print", (Bool false)); - ("print_in_place", (Bool false)); - ("force", (Bool false)); - ("fuel", Unset); - ("ifuel", Unset); - ("initial_fuel", (Int (Prims.of_int (2)))); - ("initial_ifuel", (Int Prims.int_one)); - ("keep_query_captions", (Bool true)); - ("lax", (Bool false)); - ("load", (List [])); - ("load_cmxs", (List [])); - ("log_queries", (Bool false)); - ("log_types", (Bool false)); - ("max_fuel", (Int (Prims.of_int (8)))); - ("max_ifuel", (Int (Prims.of_int (2)))); - ("MLish", (Bool false)); - ("no_default_includes", (Bool false)); - ("no_extract", (List [])); - ("no_location_info", (Bool false)); - ("no_smt", (Bool false)); - ("no_plugins", (Bool false)); - ("no_tactics", (Bool false)); - ("normalize_pure_terms_for_extraction", (Bool false)); - ("odir", Unset); - ("prims", Unset); - ("pretype", (Bool true)); - ("prims_ref", Unset); - ("print_bound_var_types", (Bool false)); - ("print_effect_args", (Bool false)); - ("print_expected_failures", (Bool false)); - ("print_full_names", (Bool false)); - ("print_implicits", (Bool false)); - ("print_universes", (Bool false)); - ("print_z3_statistics", (Bool false)); - ("prn", (Bool false)); - ("quake", (Int Prims.int_zero)); - ("quake_lo", (Int Prims.int_one)); - ("quake_hi", (Int Prims.int_one)); - ("quake_keep", (Bool false)); - ("query_stats", (Bool false)); - ("record_hints", (Bool false)); - ("record_options", (Bool false)); - ("report_assumes", Unset); - ("retry", (Bool false)); - ("reuse_hint_for", Unset); - ("silent", (Bool false)); - ("smt", Unset); - ("smtencoding.elim_box", (Bool false)); - ("smtencoding.nl_arith_repr", (String "boxwrap")); - ("smtencoding.l_arith_repr", (String "boxwrap")); - ("smtencoding.valid_intro", (Bool true)); - ("smtencoding.valid_elim", (Bool false)); - ("split_queries", (Bool false)); - ("tactics_failhard", (Bool false)); - ("tactics_info", (Bool false)); - ("tactic_raw_binders", (Bool false)); - ("tactic_trace", (Bool false)); - ("tactic_trace_d", (Int Prims.int_zero)); - ("tcnorm", (Bool true)); - ("timing", (Bool false)); - ("trace_error", (Bool false)); - ("ugly", (Bool false)); - ("unthrottle_inductives", (Bool false)); - ("unsafe_tactic_exec", (Bool false)); - ("use_native_tactics", Unset); - ("use_eq_at_higher_order", (Bool false)); - ("use_hints", (Bool false)); - ("use_hint_hashes", (Bool false)); - ("using_facts_from", Unset); - ("verify_module", (List [])); - ("warn_default_effects", (Bool false)); - ("z3refresh", (Bool false)); - ("z3rlimit", (Int (Prims.of_int (5)))); - ("z3rlimit_factor", (Int Prims.int_one)); - ("z3seed", (Int Prims.int_zero)); - ("z3cliopt", (List [])); - ("z3smtopt", (List [])); - ("__no_positivity", (Bool false)); - ("__tactics_nbe", (Bool false)); - ("warn_error", (List [])); - ("use_nbe", (Bool false)); - ("use_nbe_for_extraction", (Bool false)); - ("trivial_pre_for_unannotated_effectful_fns", (Bool true)); - ("profile_group_by_decl", (Bool false)); - ("profile_component", Unset); - ("profile", Unset)] -let (init : unit -> unit) = - fun uu___ -> - let o = internal_peek () in - FStar_Compiler_Util.smap_clear o; - FStar_Compiler_Effect.op_Bar_Greater defaults - (FStar_Compiler_List.iter set_option') -let (clear : unit -> unit) = - fun uu___ -> - let o = FStar_Compiler_Util.smap_create (Prims.of_int (50)) in - FStar_Compiler_Effect.op_Colon_Equals fstar_options [[o]]; init () -let (_run : unit) = clear () -let (get_option : Prims.string -> option_val) = - fun s -> - let uu___ = - let uu___1 = internal_peek () in - FStar_Compiler_Util.smap_try_find uu___1 s in - match uu___ with - | FStar_Pervasives_Native.None -> - let uu___1 = - let uu___2 = FStar_String.op_Hat s " not found" in - FStar_String.op_Hat "Impossible: option " uu___2 in - failwith uu___1 - | FStar_Pervasives_Native.Some s1 -> s1 -let (set_verification_options : optionstate -> unit) = - fun o -> - let verifopts = - ["initial_fuel"; - "max_fuel"; - "initial_ifuel"; - "max_ifuel"; - "detail_errors"; - "detail_hint_replay"; - "no_smt"; - "quake"; - "retry"; - "smtencoding.elim_box"; - "smtencoding.nl_arith_repr"; - "smtencoding.l_arith_repr"; - "smtencoding.valid_intro"; - "smtencoding.valid_elim"; - "tcnorm"; - "no_plugins"; - "no_tactics"; - "z3cliopt"; - "z3smtopt"; - "z3refresh"; - "z3rlimit"; - "z3rlimit_factor"; - "z3seed"; - "trivial_pre_for_unannotated_effectful_fns"] in - FStar_Compiler_List.iter - (fun k -> - let uu___ = - let uu___1 = FStar_Compiler_Util.smap_try_find o k in - FStar_Compiler_Effect.op_Bar_Greater uu___1 - FStar_Compiler_Util.must in - set_option k uu___) verifopts -let lookup_opt : 'uuuuu . Prims.string -> (option_val -> 'uuuuu) -> 'uuuuu = - fun s -> fun c -> let uu___ = get_option s in c uu___ -let (get_abort_on : unit -> Prims.int) = - fun uu___ -> lookup_opt "abort_on" as_int -let (get_admit_smt_queries : unit -> Prims.bool) = - fun uu___ -> lookup_opt "admit_smt_queries" as_bool -let (get_admit_except : unit -> Prims.string FStar_Pervasives_Native.option) - = fun uu___ -> lookup_opt "admit_except" (as_option as_string) -let (get_compat_pre_core : unit -> Prims.int FStar_Pervasives_Native.option) - = fun uu___ -> lookup_opt "compat_pre_core" (as_option as_int) -let (get_compat_pre_typed_indexed_effects : unit -> Prims.bool) = - fun uu___ -> lookup_opt "compat_pre_typed_indexed_effects" as_bool -let (get_disallow_unification_guards : unit -> Prims.bool) = - fun uu___ -> lookup_opt "disallow_unification_guards" as_bool -let (get_already_cached : - unit -> Prims.string Prims.list FStar_Pervasives_Native.option) = - fun uu___ -> lookup_opt "already_cached" (as_option (as_list as_string)) -let (get_cache_checked_modules : unit -> Prims.bool) = - fun uu___ -> lookup_opt "cache_checked_modules" as_bool -let (get_cache_dir : unit -> Prims.string FStar_Pervasives_Native.option) = - fun uu___ -> lookup_opt "cache_dir" (as_option as_string) -let (get_cache_off : unit -> Prims.bool) = - fun uu___ -> lookup_opt "cache_off" as_bool -let (get_print_cache_version : unit -> Prims.bool) = - fun uu___ -> lookup_opt "print_cache_version" as_bool -let (get_cmi : unit -> Prims.bool) = fun uu___ -> lookup_opt "cmi" as_bool -let (get_codegen : unit -> Prims.string FStar_Pervasives_Native.option) = - fun uu___ -> lookup_opt "codegen" (as_option as_string) -let (get_codegen_lib : unit -> Prims.string Prims.list) = - fun uu___ -> lookup_opt "codegen-lib" (as_list as_string) -let (get_debug : unit -> Prims.string Prims.list) = - fun uu___ -> lookup_opt "debug" as_comma_string_list -let (get_debug_level : unit -> Prims.string Prims.list) = - fun uu___ -> lookup_opt "debug_level" as_comma_string_list -let (get_defensive : unit -> Prims.string) = - fun uu___ -> lookup_opt "defensive" as_string -let (get_dep : unit -> Prims.string FStar_Pervasives_Native.option) = - fun uu___ -> lookup_opt "dep" (as_option as_string) -let (get_detail_errors : unit -> Prims.bool) = - fun uu___ -> lookup_opt "detail_errors" as_bool -let (get_detail_hint_replay : unit -> Prims.bool) = - fun uu___ -> lookup_opt "detail_hint_replay" as_bool -let (get_dump_module : unit -> Prims.string Prims.list) = - fun uu___ -> lookup_opt "dump_module" (as_list as_string) -let (get_eager_subtyping : unit -> Prims.bool) = - fun uu___ -> lookup_opt "eager_subtyping" as_bool -let (get_error_contexts : unit -> Prims.bool) = - fun uu___ -> lookup_opt "error_contexts" as_bool -let (get_expose_interfaces : unit -> Prims.bool) = - fun uu___ -> lookup_opt "expose_interfaces" as_bool -let (get_extract : - unit -> Prims.string Prims.list FStar_Pervasives_Native.option) = - fun uu___ -> lookup_opt "extract" (as_option (as_list as_string)) -let (get_extract_module : unit -> Prims.string Prims.list) = - fun uu___ -> lookup_opt "extract_module" (as_list as_string) -let (get_extract_namespace : unit -> Prims.string Prims.list) = - fun uu___ -> lookup_opt "extract_namespace" (as_list as_string) -let (get_force : unit -> Prims.bool) = - fun uu___ -> lookup_opt "force" as_bool -let (get_hide_uvar_nums : unit -> Prims.bool) = - fun uu___ -> lookup_opt "hide_uvar_nums" as_bool -let (get_hint_info : unit -> Prims.bool) = - fun uu___ -> lookup_opt "hint_info" as_bool -let (get_hint_dir : unit -> Prims.string FStar_Pervasives_Native.option) = - fun uu___ -> lookup_opt "hint_dir" (as_option as_string) -let (get_hint_file : unit -> Prims.string FStar_Pervasives_Native.option) = - fun uu___ -> lookup_opt "hint_file" (as_option as_string) -let (get_in : unit -> Prims.bool) = fun uu___ -> lookup_opt "in" as_bool -let (get_ide : unit -> Prims.bool) = fun uu___ -> lookup_opt "ide" as_bool -let (get_ide_id_info_off : unit -> Prims.bool) = - fun uu___ -> lookup_opt "ide_id_info_off" as_bool -let (get_lsp : unit -> Prims.bool) = fun uu___ -> lookup_opt "lsp" as_bool -let (get_include : unit -> Prims.string Prims.list) = - fun uu___ -> lookup_opt "include" (as_list as_string) -let (get_print : unit -> Prims.bool) = - fun uu___ -> lookup_opt "print" as_bool -let (get_print_in_place : unit -> Prims.bool) = - fun uu___ -> lookup_opt "print_in_place" as_bool -let (get_initial_fuel : unit -> Prims.int) = - fun uu___ -> lookup_opt "initial_fuel" as_int -let (get_initial_ifuel : unit -> Prims.int) = - fun uu___ -> lookup_opt "initial_ifuel" as_int -let (get_keep_query_captions : unit -> Prims.bool) = - fun uu___ -> lookup_opt "keep_query_captions" as_bool -let (get_lax : unit -> Prims.bool) = fun uu___ -> lookup_opt "lax" as_bool -let (get_load : unit -> Prims.string Prims.list) = - fun uu___ -> lookup_opt "load" (as_list as_string) -let (get_load_cmxs : unit -> Prims.string Prims.list) = - fun uu___ -> lookup_opt "load_cmxs" (as_list as_string) -let (get_log_queries : unit -> Prims.bool) = - fun uu___ -> lookup_opt "log_queries" as_bool -let (get_log_types : unit -> Prims.bool) = - fun uu___ -> lookup_opt "log_types" as_bool -let (get_max_fuel : unit -> Prims.int) = - fun uu___ -> lookup_opt "max_fuel" as_int -let (get_max_ifuel : unit -> Prims.int) = - fun uu___ -> lookup_opt "max_ifuel" as_int -let (get_MLish : unit -> Prims.bool) = - fun uu___ -> lookup_opt "MLish" as_bool -let (get_no_default_includes : unit -> Prims.bool) = - fun uu___ -> lookup_opt "no_default_includes" as_bool -let (get_no_extract : unit -> Prims.string Prims.list) = - fun uu___ -> lookup_opt "no_extract" (as_list as_string) -let (get_no_location_info : unit -> Prims.bool) = - fun uu___ -> lookup_opt "no_location_info" as_bool -let (get_no_plugins : unit -> Prims.bool) = - fun uu___ -> lookup_opt "no_plugins" as_bool -let (get_no_smt : unit -> Prims.bool) = - fun uu___ -> lookup_opt "no_smt" as_bool -let (get_normalize_pure_terms_for_extraction : unit -> Prims.bool) = - fun uu___ -> lookup_opt "normalize_pure_terms_for_extraction" as_bool -let (get_odir : unit -> Prims.string FStar_Pervasives_Native.option) = - fun uu___ -> lookup_opt "odir" (as_option as_string) -let (get_ugly : unit -> Prims.bool) = fun uu___ -> lookup_opt "ugly" as_bool -let (get_prims : unit -> Prims.string FStar_Pervasives_Native.option) = - fun uu___ -> lookup_opt "prims" (as_option as_string) -let (get_print_bound_var_types : unit -> Prims.bool) = - fun uu___ -> lookup_opt "print_bound_var_types" as_bool -let (get_print_effect_args : unit -> Prims.bool) = - fun uu___ -> lookup_opt "print_effect_args" as_bool -let (get_print_expected_failures : unit -> Prims.bool) = - fun uu___ -> lookup_opt "print_expected_failures" as_bool -let (get_print_full_names : unit -> Prims.bool) = - fun uu___ -> lookup_opt "print_full_names" as_bool -let (get_print_implicits : unit -> Prims.bool) = - fun uu___ -> lookup_opt "print_implicits" as_bool -let (get_print_universes : unit -> Prims.bool) = - fun uu___ -> lookup_opt "print_universes" as_bool -let (get_print_z3_statistics : unit -> Prims.bool) = - fun uu___ -> lookup_opt "print_z3_statistics" as_bool -let (get_prn : unit -> Prims.bool) = fun uu___ -> lookup_opt "prn" as_bool -let (get_quake_lo : unit -> Prims.int) = - fun uu___ -> lookup_opt "quake_lo" as_int -let (get_quake_hi : unit -> Prims.int) = - fun uu___ -> lookup_opt "quake_hi" as_int -let (get_quake_keep : unit -> Prims.bool) = - fun uu___ -> lookup_opt "quake_keep" as_bool -let (get_query_stats : unit -> Prims.bool) = - fun uu___ -> lookup_opt "query_stats" as_bool -let (get_record_hints : unit -> Prims.bool) = - fun uu___ -> lookup_opt "record_hints" as_bool -let (get_record_options : unit -> Prims.bool) = - fun uu___ -> lookup_opt "record_options" as_bool -let (get_retry : unit -> Prims.bool) = - fun uu___ -> lookup_opt "retry" as_bool -let (get_reuse_hint_for : - unit -> Prims.string FStar_Pervasives_Native.option) = - fun uu___ -> lookup_opt "reuse_hint_for" (as_option as_string) -let (get_report_assumes : - unit -> Prims.string FStar_Pervasives_Native.option) = - fun uu___ -> lookup_opt "report_assumes" (as_option as_string) -let (get_silent : unit -> Prims.bool) = - fun uu___ -> lookup_opt "silent" as_bool -let (get_smt : unit -> Prims.string FStar_Pervasives_Native.option) = - fun uu___ -> lookup_opt "smt" (as_option as_string) -let (get_smtencoding_elim_box : unit -> Prims.bool) = - fun uu___ -> lookup_opt "smtencoding.elim_box" as_bool -let (get_smtencoding_nl_arith_repr : unit -> Prims.string) = - fun uu___ -> lookup_opt "smtencoding.nl_arith_repr" as_string -let (get_smtencoding_l_arith_repr : unit -> Prims.string) = - fun uu___ -> lookup_opt "smtencoding.l_arith_repr" as_string -let (get_smtencoding_valid_intro : unit -> Prims.bool) = - fun uu___ -> lookup_opt "smtencoding.valid_intro" as_bool -let (get_smtencoding_valid_elim : unit -> Prims.bool) = - fun uu___ -> lookup_opt "smtencoding.valid_elim" as_bool -let (get_split_queries : unit -> Prims.bool) = - fun uu___ -> lookup_opt "split_queries" as_bool -let (get_tactic_raw_binders : unit -> Prims.bool) = - fun uu___ -> lookup_opt "tactic_raw_binders" as_bool -let (get_tactics_failhard : unit -> Prims.bool) = - fun uu___ -> lookup_opt "tactics_failhard" as_bool -let (get_tactics_info : unit -> Prims.bool) = - fun uu___ -> lookup_opt "tactics_info" as_bool -let (get_tactic_trace : unit -> Prims.bool) = - fun uu___ -> lookup_opt "tactic_trace" as_bool -let (get_tactic_trace_d : unit -> Prims.int) = - fun uu___ -> lookup_opt "tactic_trace_d" as_int -let (get_tactics_nbe : unit -> Prims.bool) = - fun uu___ -> lookup_opt "__tactics_nbe" as_bool -let (get_tcnorm : unit -> Prims.bool) = - fun uu___ -> lookup_opt "tcnorm" as_bool -let (get_timing : unit -> Prims.bool) = - fun uu___ -> lookup_opt "timing" as_bool -let (get_trace_error : unit -> Prims.bool) = - fun uu___ -> lookup_opt "trace_error" as_bool -let (get_unthrottle_inductives : unit -> Prims.bool) = - fun uu___ -> lookup_opt "unthrottle_inductives" as_bool -let (get_unsafe_tactic_exec : unit -> Prims.bool) = - fun uu___ -> lookup_opt "unsafe_tactic_exec" as_bool -let (get_use_eq_at_higher_order : unit -> Prims.bool) = - fun uu___ -> lookup_opt "use_eq_at_higher_order" as_bool -let (get_use_hints : unit -> Prims.bool) = - fun uu___ -> lookup_opt "use_hints" as_bool -let (get_use_hint_hashes : unit -> Prims.bool) = - fun uu___ -> lookup_opt "use_hint_hashes" as_bool -let (get_use_native_tactics : - unit -> Prims.string FStar_Pervasives_Native.option) = - fun uu___ -> lookup_opt "use_native_tactics" (as_option as_string) -let (get_no_tactics : unit -> Prims.bool) = - fun uu___ -> lookup_opt "no_tactics" as_bool -let (get_using_facts_from : - unit -> Prims.string Prims.list FStar_Pervasives_Native.option) = - fun uu___ -> lookup_opt "using_facts_from" (as_option (as_list as_string)) -let (get_verify_module : unit -> Prims.string Prims.list) = - fun uu___ -> lookup_opt "verify_module" (as_list as_string) -let (get_version : unit -> Prims.bool) = - fun uu___ -> lookup_opt "version" as_bool -let (get_warn_default_effects : unit -> Prims.bool) = - fun uu___ -> lookup_opt "warn_default_effects" as_bool -let (get_z3cliopt : unit -> Prims.string Prims.list) = - fun uu___ -> lookup_opt "z3cliopt" (as_list as_string) -let (get_z3smtopt : unit -> Prims.string Prims.list) = - fun uu___ -> lookup_opt "z3smtopt" (as_list as_string) -let (get_z3refresh : unit -> Prims.bool) = - fun uu___ -> lookup_opt "z3refresh" as_bool -let (get_z3rlimit : unit -> Prims.int) = - fun uu___ -> lookup_opt "z3rlimit" as_int -let (get_z3rlimit_factor : unit -> Prims.int) = - fun uu___ -> lookup_opt "z3rlimit_factor" as_int -let (get_z3seed : unit -> Prims.int) = - fun uu___ -> lookup_opt "z3seed" as_int -let (get_no_positivity : unit -> Prims.bool) = - fun uu___ -> lookup_opt "__no_positivity" as_bool -let (get_warn_error : unit -> Prims.string Prims.list) = - fun uu___ -> lookup_opt "warn_error" (as_list as_string) -let (get_use_nbe : unit -> Prims.bool) = - fun uu___ -> lookup_opt "use_nbe" as_bool -let (get_use_nbe_for_extraction : unit -> Prims.bool) = - fun uu___ -> lookup_opt "use_nbe_for_extraction" as_bool -let (get_trivial_pre_for_unannotated_effectful_fns : unit -> Prims.bool) = - fun uu___ -> lookup_opt "trivial_pre_for_unannotated_effectful_fns" as_bool -let (get_profile : - unit -> Prims.string Prims.list FStar_Pervasives_Native.option) = - fun uu___ -> lookup_opt "profile" (as_option (as_list as_string)) -let (get_profile_group_by_decl : unit -> Prims.bool) = - fun uu___ -> lookup_opt "profile_group_by_decl" as_bool -let (get_profile_component : - unit -> Prims.string Prims.list FStar_Pervasives_Native.option) = - fun uu___ -> lookup_opt "profile_component" (as_option (as_list as_string)) -let (dlevel : Prims.string -> debug_level_t) = - fun uu___ -> - match uu___ with - | "Low" -> Low - | "Medium" -> Medium - | "High" -> High - | "Extreme" -> Extreme - | s -> Other s -let (one_debug_level_geq : debug_level_t -> debug_level_t -> Prims.bool) = - fun l1 -> - fun l2 -> - match l1 with - | Other uu___ -> l1 = l2 - | Low -> l1 = l2 - | Medium -> (l2 = Low) || (l2 = Medium) - | High -> ((l2 = Low) || (l2 = Medium)) || (l2 = High) - | Extreme -> - (((l2 = Low) || (l2 = Medium)) || (l2 = High)) || (l2 = Extreme) -let (debug_level_geq : debug_level_t -> Prims.bool) = - fun l2 -> - let uu___ = get_debug_level () in - FStar_Compiler_Effect.op_Bar_Greater uu___ - (FStar_Compiler_Util.for_some - (fun l1 -> one_debug_level_geq (dlevel l1) l2)) -let (universe_include_path_base_dirs : Prims.string Prims.list) = - let sub_dirs = ["legacy"; "experimental"; ".cache"] in - FStar_Compiler_Effect.op_Bar_Greater ["/ulib"; "/lib/fstar"] - (FStar_Compiler_List.collect - (fun d -> - let uu___ = - FStar_Compiler_Effect.op_Bar_Greater sub_dirs - (FStar_Compiler_List.map - (fun s -> - let uu___1 = FStar_String.op_Hat "/" s in - FStar_String.op_Hat d uu___1)) in - d :: uu___)) -let (_version : Prims.string FStar_Compiler_Effect.ref) = - FStar_Compiler_Util.mk_ref "" -let (_platform : Prims.string FStar_Compiler_Effect.ref) = - FStar_Compiler_Util.mk_ref "" -let (_compiler : Prims.string FStar_Compiler_Effect.ref) = - FStar_Compiler_Util.mk_ref "" -let (_date : Prims.string FStar_Compiler_Effect.ref) = - FStar_Compiler_Util.mk_ref " not set" -let (_commit : Prims.string FStar_Compiler_Effect.ref) = - FStar_Compiler_Util.mk_ref "" -let (display_version : unit -> unit) = - fun uu___ -> - let uu___1 = - let uu___2 = FStar_Compiler_Effect.op_Bang _version in - let uu___3 = FStar_Compiler_Effect.op_Bang _platform in - let uu___4 = FStar_Compiler_Effect.op_Bang _compiler in - let uu___5 = FStar_Compiler_Effect.op_Bang _date in - let uu___6 = FStar_Compiler_Effect.op_Bang _commit in - FStar_Compiler_Util.format5 - "F* %s\nplatform=%s\ncompiler=%s\ndate=%s\ncommit=%s\n" uu___2 uu___3 - uu___4 uu___5 uu___6 in - FStar_Compiler_Util.print_string uu___1 -let display_usage_aux : - 'uuuuu 'uuuuu1 . - ('uuuuu * Prims.string * 'uuuuu1 FStar_Getopt.opt_variant * Prims.string) - Prims.list -> unit - = - fun specs -> - FStar_Compiler_Util.print_string - "fstar.exe [options] file[s] [@respfile...]\n"; - (let uu___2 = - let uu___3 = FStar_Compiler_Util.colorize_bold "@" in - FStar_Compiler_Util.format1 - " %srespfile read options from respfile\n" uu___3 in - FStar_Compiler_Util.print_string uu___2); - FStar_Compiler_List.iter - (fun uu___2 -> - match uu___2 with - | (uu___3, flag, p, doc) -> - (match p with - | FStar_Getopt.ZeroArgs ig -> - if doc = "" - then - let uu___4 = - let uu___5 = FStar_Compiler_Util.colorize_bold flag in - FStar_Compiler_Util.format1 " --%s\n" uu___5 in - FStar_Compiler_Util.print_string uu___4 - else - (let uu___5 = - let uu___6 = FStar_Compiler_Util.colorize_bold flag in - FStar_Compiler_Util.format2 " --%s %s\n" uu___6 doc in - FStar_Compiler_Util.print_string uu___5) - | FStar_Getopt.OneArg (uu___4, argname) -> - if doc = "" - then - let uu___5 = - let uu___6 = FStar_Compiler_Util.colorize_bold flag in - let uu___7 = FStar_Compiler_Util.colorize_bold argname in - FStar_Compiler_Util.format2 " --%s %s\n" uu___6 uu___7 in - FStar_Compiler_Util.print_string uu___5 - else - (let uu___6 = - let uu___7 = FStar_Compiler_Util.colorize_bold flag in - let uu___8 = FStar_Compiler_Util.colorize_bold argname in - FStar_Compiler_Util.format3 " --%s %s %s\n" uu___7 - uu___8 doc in - FStar_Compiler_Util.print_string uu___6))) specs -let (mk_spec : - (FStar_BaseTypes.char * Prims.string * option_val FStar_Getopt.opt_variant - * Prims.string) -> FStar_Getopt.opt) - = - fun o -> - let uu___ = o in - match uu___ with - | (ns, name, arg, desc) -> - let arg1 = - match arg with - | FStar_Getopt.ZeroArgs f -> - let g uu___1 = let uu___2 = f () in set_option name uu___2 in - FStar_Getopt.ZeroArgs g - | FStar_Getopt.OneArg (f, d) -> - let g x = let uu___1 = f x in set_option name uu___1 in - FStar_Getopt.OneArg (g, d) in - (ns, name, arg1, desc) -let (accumulated_option : Prims.string -> option_val -> option_val) = - fun name -> - fun value -> - let prev_values = - let uu___ = lookup_opt name (as_option as_list') in - FStar_Compiler_Util.dflt [] uu___ in - List (value :: prev_values) -let (reverse_accumulated_option : Prims.string -> option_val -> option_val) = - fun name -> - fun value -> - let prev_values = - let uu___ = lookup_opt name (as_option as_list') in - FStar_Compiler_Util.dflt [] uu___ in - List (FStar_Compiler_List.op_At prev_values [value]) -let accumulate_string : - 'uuuuu . Prims.string -> ('uuuuu -> Prims.string) -> 'uuuuu -> unit = - fun name -> - fun post_processor -> - fun value -> - let uu___ = - let uu___1 = let uu___2 = post_processor value in String uu___2 in - accumulated_option name uu___1 in - set_option name uu___ -let (add_extract_module : Prims.string -> unit) = - fun s -> accumulate_string "extract_module" FStar_String.lowercase s -let (add_extract_namespace : Prims.string -> unit) = - fun s -> accumulate_string "extract_namespace" FStar_String.lowercase s -let (add_verify_module : Prims.string -> unit) = - fun s -> accumulate_string "verify_module" FStar_String.lowercase s -exception InvalidArgument of Prims.string -let (uu___is_InvalidArgument : Prims.exn -> Prims.bool) = - fun projectee -> - match projectee with | InvalidArgument uu___ -> true | uu___ -> false -let (__proj__InvalidArgument__item__uu___ : Prims.exn -> Prims.string) = - fun projectee -> match projectee with | InvalidArgument uu___ -> uu___ -let rec (parse_opt_val : - Prims.string -> opt_type -> Prims.string -> option_val) = - fun opt_name -> - fun typ -> - fun str_val -> - try - (fun uu___ -> - match () with - | () -> - (match typ with - | Const c -> c - | IntStr uu___1 -> - let uu___2 = - FStar_Compiler_Util.safe_int_of_string str_val in - (match uu___2 with - | FStar_Pervasives_Native.Some v -> Int v - | FStar_Pervasives_Native.None -> - FStar_Compiler_Effect.raise - (InvalidArgument opt_name)) - | BoolStr -> - let uu___1 = - if str_val = "true" - then true - else - if str_val = "false" - then false - else - FStar_Compiler_Effect.raise - (InvalidArgument opt_name) in - Bool uu___1 - | PathStr uu___1 -> Path str_val - | SimpleStr uu___1 -> String str_val - | EnumStr strs -> - if FStar_Compiler_List.mem str_val strs - then String str_val - else - FStar_Compiler_Effect.raise - (InvalidArgument opt_name) - | OpenEnumStr uu___1 -> String str_val - | PostProcessed (pp, elem_spec) -> - let uu___1 = parse_opt_val opt_name elem_spec str_val in - pp uu___1 - | Accumulated elem_spec -> - let v = parse_opt_val opt_name elem_spec str_val in - accumulated_option opt_name v - | ReverseAccumulated elem_spec -> - let v = parse_opt_val opt_name elem_spec str_val in - reverse_accumulated_option opt_name v - | WithSideEffect (side_effect, elem_spec) -> - (side_effect (); - parse_opt_val opt_name elem_spec str_val))) () - with - | InvalidArgument opt_name1 -> - let uu___1 = - FStar_Compiler_Util.format1 "Invalid argument to --%s" - opt_name1 in - failwith uu___1 -let rec (desc_of_opt_type : - opt_type -> Prims.string FStar_Pervasives_Native.option) = - fun typ -> - let desc_of_enum cases = - let uu___ = - let uu___1 = FStar_String.op_Hat (FStar_String.concat "|" cases) "]" in - FStar_String.op_Hat "[" uu___1 in - FStar_Pervasives_Native.Some uu___ in - match typ with - | Const c -> FStar_Pervasives_Native.None - | IntStr desc -> FStar_Pervasives_Native.Some desc - | BoolStr -> desc_of_enum ["true"; "false"] - | PathStr desc -> FStar_Pervasives_Native.Some desc - | SimpleStr desc -> FStar_Pervasives_Native.Some desc - | EnumStr strs -> desc_of_enum strs - | OpenEnumStr (strs, desc) -> - desc_of_enum (FStar_Compiler_List.op_At strs [desc]) - | PostProcessed (uu___, elem_spec) -> desc_of_opt_type elem_spec - | Accumulated elem_spec -> desc_of_opt_type elem_spec - | ReverseAccumulated elem_spec -> desc_of_opt_type elem_spec - | WithSideEffect (uu___, elem_spec) -> desc_of_opt_type elem_spec -let (arg_spec_of_opt_type : - Prims.string -> opt_type -> option_val FStar_Getopt.opt_variant) = - fun opt_name -> - fun typ -> - let parser = parse_opt_val opt_name typ in - let uu___ = desc_of_opt_type typ in - match uu___ with - | FStar_Pervasives_Native.None -> - FStar_Getopt.ZeroArgs ((fun uu___1 -> parser "")) - | FStar_Pervasives_Native.Some desc -> - FStar_Getopt.OneArg (parser, desc) -let (pp_validate_dir : option_val -> option_val) = - fun p -> let pp = as_string p in FStar_Compiler_Util.mkdir false pp; p -let (pp_lowercase : option_val -> option_val) = - fun s -> - let uu___ = let uu___1 = as_string s in FStar_String.lowercase uu___1 in - String uu___ -let (abort_counter : Prims.int FStar_Compiler_Effect.ref) = - FStar_Compiler_Util.mk_ref Prims.int_zero -let (interp_quake_arg : Prims.string -> (Prims.int * Prims.int * Prims.bool)) - = - fun s -> - let ios = FStar_Compiler_Util.int_of_string in - match FStar_Compiler_Util.split s "/" with - | f::[] -> - let uu___ = ios f in let uu___1 = ios f in (uu___, uu___1, false) - | f1::f2::[] -> - if f2 = "k" - then - let uu___ = ios f1 in let uu___1 = ios f1 in (uu___, uu___1, true) - else - (let uu___1 = ios f1 in - let uu___2 = ios f2 in (uu___1, uu___2, false)) - | f1::f2::k::[] -> - if k = "k" - then - let uu___ = ios f1 in let uu___1 = ios f2 in (uu___, uu___1, true) - else failwith "unexpected value for --quake" - | uu___ -> failwith "unexpected value for --quake" -let (uu___447 : (((Prims.string -> unit) -> unit) * (Prims.string -> unit))) - = - let cb = FStar_Compiler_Util.mk_ref FStar_Pervasives_Native.None in - let set1 f = - FStar_Compiler_Effect.op_Colon_Equals cb (FStar_Pervasives_Native.Some f) in - let call msg = - let uu___ = FStar_Compiler_Effect.op_Bang cb in - match uu___ with - | FStar_Pervasives_Native.None -> () - | FStar_Pervasives_Native.Some f -> f msg in - (set1, call) -let (set_option_warning_callback_aux : (Prims.string -> unit) -> unit) = - match uu___447 with - | (set_option_warning_callback_aux1, option_warning_callback) -> - set_option_warning_callback_aux1 -let (option_warning_callback : Prims.string -> unit) = - match uu___447 with - | (set_option_warning_callback_aux1, option_warning_callback1) -> - option_warning_callback1 -let (set_option_warning_callback : (Prims.string -> unit) -> unit) = - fun f -> set_option_warning_callback_aux f -let rec (specs_with_types : - Prims.bool -> - (FStar_BaseTypes.char * Prims.string * opt_type * Prims.string) - Prims.list) - = - fun warn_unsafe -> - [(FStar_Getopt.noshort, "abort_on", - (PostProcessed - (((fun uu___ -> - match uu___ with - | Int x -> - (FStar_Compiler_Effect.op_Colon_Equals abort_counter x; - Int x) - | x -> failwith "?")), (IntStr "non-negative integer"))), - "Abort on the n-th error or warning raised. Useful in combination with --trace_error. Count starts at 1, use 0 to disable. (default 0)"); - (FStar_Getopt.noshort, "admit_smt_queries", - (WithSideEffect - (((fun uu___ -> - if warn_unsafe - then option_warning_callback "admit_smt_queries" - else ())), BoolStr)), - "Admit SMT queries, unsafe! (default 'false')"); - (FStar_Getopt.noshort, "admit_except", - (WithSideEffect - (((fun uu___ -> - if warn_unsafe - then option_warning_callback "admit_except" - else ())), (SimpleStr "[symbol|(symbol, id)]"))), - "Admit all queries, except those with label ( symbol, id)) (e.g. --admit_except '(FStar.Fin.pigeonhole, 1)' or --admit_except FStar.Fin.pigeonhole)"); - (FStar_Getopt.noshort, "compat_pre_core", (IntStr "0, 1, 2"), - "Retain behavior of the tactic engine prior to the introduction of FStar.TypeChecker.Core (0 is most permissive, 2 is least permissive)"); - (FStar_Getopt.noshort, "compat_pre_typed_indexed_effects", - (Const (Bool true)), "Retain untyped indexed effects implicits"); - (FStar_Getopt.noshort, "disallow_unification_guards", BoolStr, - "Fail if the SMT guard are produced when the tactic engine re-checks solutions produced by the unifier (default 'false')"); - (FStar_Getopt.noshort, "already_cached", - (Accumulated - (SimpleStr - "One or more space-separated occurrences of '[+|-]( * | namespace | module)'")), - "\n\t\tExpects all modules whose names or namespaces match the provided options \n\t\t\tto already have valid .checked files in the include path"); - (FStar_Getopt.noshort, "cache_checked_modules", (Const (Bool true)), - "Write a '.checked' file for each module after verification and read from it if present, instead of re-verifying"); - (FStar_Getopt.noshort, "cache_dir", - (PostProcessed (pp_validate_dir, (PathStr "dir"))), - "Read and write .checked and .checked.lax in directory dir"); - (FStar_Getopt.noshort, "cache_off", (Const (Bool true)), - "Do not read or write any .checked files"); - (FStar_Getopt.noshort, "print_cache_version", (Const (Bool true)), - "Print the version for .checked files and exit."); - (FStar_Getopt.noshort, "cmi", (Const (Bool true)), - "Inline across module interfaces during extraction (aka. cross-module inlining)"); - (FStar_Getopt.noshort, "codegen", - (EnumStr ["OCaml"; "FSharp"; "krml"; "Plugin"]), - "Generate code for further compilation to executable code, or build a compiler plugin"); - (FStar_Getopt.noshort, "codegen-lib", - (Accumulated (SimpleStr "namespace")), - "External runtime library (i.e. M.N.x extracts to M.N.X instead of M_N.x)"); - (FStar_Getopt.noshort, "debug", (Accumulated (SimpleStr "module_name")), - "Print lots of debugging information while checking module"); - (FStar_Getopt.noshort, "debug_level", - (Accumulated - (OpenEnumStr (["Low"; "Medium"; "High"; "Extreme"], "..."))), - "Control the verbosity of debugging info"); - (FStar_Getopt.noshort, "defensive", - (EnumStr ["no"; "warn"; "error"; "abort"]), - "Enable several internal sanity checks, useful to track bugs and report issues.\n\t\tif 'no', no checks are performed\n\t\tif 'warn', checks are performed and raise a warning when they fail\n\t\tif 'error, like 'warn', but the compiler raises a hard error instead \n\t\tif 'abort, like 'warn', but the compiler immediately aborts on an error\n\t\t(default 'no')"); - (FStar_Getopt.noshort, "dep", (EnumStr ["make"; "graph"; "full"; "raw"]), - "Output the transitive closure of the full dependency graph in three formats:\n\t 'graph': a format suitable the 'dot' tool from 'GraphViz'\n\t 'full': a format suitable for 'make', including dependences for producing .ml and .krml files\n\t 'make': (deprecated) a format suitable for 'make', including only dependences among source files"); - (FStar_Getopt.noshort, "detail_errors", (Const (Bool true)), - "Emit a detailed error report by asking the SMT solver many queries; will take longer"); - (FStar_Getopt.noshort, "detail_hint_replay", (Const (Bool true)), - "Emit a detailed report for proof whose unsat core fails to replay"); - (FStar_Getopt.noshort, "dump_module", - (Accumulated (SimpleStr "module_name")), ""); - (FStar_Getopt.noshort, "eager_subtyping", (Const (Bool true)), - "Try to solve subtyping constraints at each binder (loses precision but may be slightly more efficient)"); - (FStar_Getopt.noshort, "error_contexts", BoolStr, - "Print context information for each error or warning raised (default false)"); - (FStar_Getopt.noshort, "extract", - (Accumulated - (SimpleStr - "One or more semicolon separated occurrences of '[TargetName:]ModuleSelector'")), - "\n\t\tExtract only those modules whose names or namespaces match the provided options.\n\t\t\t'TargetName' ranges over {OCaml, krml, FSharp, Plugin}.\n\t\t\tA 'ModuleSelector' is a space or comma-separated list of '[+|-]( * | namespace | module)'.\n\t\t\tFor example --extract 'OCaml:A -A.B' --extract 'krml:A -A.C' --extract '*' means\n\t\t\t\tfor OCaml, extract everything in the A namespace only except A.B;\n\t\t\t\tfor krml, extract everything in the A namespace only except A.C;\n\t\t\t\tfor everything else, extract everything.\n\t\t\tNote, the '+' is optional: --extract '+A' and --extract 'A' mean the same thing.\n\t\t\tNote also that '--extract A' applies both to a module named 'A' and to any module in the 'A' namespace\n\t\tMultiple uses of this option accumulate, e.g., --extract A --extract B is interpreted as --extract 'A B'."); - (FStar_Getopt.noshort, "extract_module", - (Accumulated (PostProcessed (pp_lowercase, (SimpleStr "module_name")))), - "Deprecated: use --extract instead; Only extract the specified modules (instead of the possibly-partial dependency graph)"); - (FStar_Getopt.noshort, "extract_namespace", - (Accumulated - (PostProcessed (pp_lowercase, (SimpleStr "namespace name")))), - "Deprecated: use --extract instead; Only extract modules in the specified namespace"); - (FStar_Getopt.noshort, "expose_interfaces", (Const (Bool true)), - "Explicitly break the abstraction imposed by the interface of any implementation file that appears on the command line (use with care!)"); - (FStar_Getopt.noshort, "hide_uvar_nums", (Const (Bool true)), - "Don't print unification variable numbers"); - (FStar_Getopt.noshort, "hint_dir", - (PostProcessed (pp_validate_dir, (PathStr "dir"))), - "Read/write hints to dir/module_name.hints (instead of placing hint-file alongside source file)"); - (FStar_Getopt.noshort, "hint_file", (PathStr "path"), - "Read/write hints to path (instead of module-specific hints files; overrides hint_dir)"); - (FStar_Getopt.noshort, "hint_info", (Const (Bool true)), - "Print information regarding hints (deprecated; use --query_stats instead)"); - (FStar_Getopt.noshort, "in", (Const (Bool true)), - "Legacy interactive mode; reads input from stdin"); - (FStar_Getopt.noshort, "ide", (Const (Bool true)), - "JSON-based interactive mode for IDEs"); - (FStar_Getopt.noshort, "ide_id_info_off", (Const (Bool true)), - "Disable identifier tables in IDE mode (temporary workaround useful in Steel)"); - (FStar_Getopt.noshort, "lsp", (Const (Bool true)), - "Language Server Protocol-based interactive mode for IDEs"); - (FStar_Getopt.noshort, "include", (ReverseAccumulated (PathStr "path")), - "A directory in which to search for files included on the command line"); - (FStar_Getopt.noshort, "print", (Const (Bool true)), - "Parses and prettyprints the files included on the command line"); - (FStar_Getopt.noshort, "print_in_place", (Const (Bool true)), - "Parses and prettyprints in place the files included on the command line"); - (102, "force", (Const (Bool true)), - "Force checking the files given as arguments even if they have valid checked files"); - (FStar_Getopt.noshort, "fuel", - (PostProcessed - (((fun uu___ -> - match uu___ with - | String s -> - let p f = - let uu___1 = FStar_Compiler_Util.int_of_string f in - Int uu___1 in - let uu___1 = - match FStar_Compiler_Util.split s "," with - | f::[] -> (f, f) - | f1::f2::[] -> (f1, f2) - | uu___2 -> failwith "unexpected value for --fuel" in - (match uu___1 with - | (min, max) -> - ((let uu___3 = p min in - set_option "initial_fuel" uu___3); - (let uu___4 = p max in set_option "max_fuel" uu___4); - String s)) - | uu___1 -> failwith "impos")), - (SimpleStr "non-negative integer or pair of non-negative integers"))), - "Set initial_fuel and max_fuel at once"); - (FStar_Getopt.noshort, "ifuel", - (PostProcessed - (((fun uu___ -> - match uu___ with - | String s -> - let p f = - let uu___1 = FStar_Compiler_Util.int_of_string f in - Int uu___1 in - let uu___1 = - match FStar_Compiler_Util.split s "," with - | f::[] -> (f, f) - | f1::f2::[] -> (f1, f2) - | uu___2 -> failwith "unexpected value for --ifuel" in - (match uu___1 with - | (min, max) -> - ((let uu___3 = p min in - set_option "initial_ifuel" uu___3); - (let uu___4 = p max in set_option "max_ifuel" uu___4); - String s)) - | uu___1 -> failwith "impos")), - (SimpleStr "non-negative integer or pair of non-negative integers"))), - "Set initial_ifuel and max_ifuel at once"); - (FStar_Getopt.noshort, "initial_fuel", (IntStr "non-negative integer"), - "Number of unrolling of recursive functions to try initially (default 2)"); - (FStar_Getopt.noshort, "initial_ifuel", (IntStr "non-negative integer"), - "Number of unrolling of inductive datatypes to try at first (default 1)"); - (FStar_Getopt.noshort, "keep_query_captions", BoolStr, - "Retain comments in the logged SMT queries (requires --log_queries; default true)"); - (FStar_Getopt.noshort, "lax", - (WithSideEffect - (((fun uu___ -> - if warn_unsafe then option_warning_callback "lax" else ())), - (Const (Bool true)))), - "Run the lax-type checker only (admit all verification conditions)"); - (FStar_Getopt.noshort, "load", (ReverseAccumulated (PathStr "module")), - "Load OCaml module, compiling it if necessary"); - (FStar_Getopt.noshort, "load_cmxs", - (ReverseAccumulated (PathStr "module")), - "Load compiled module, fails hard if the module is not already compiled"); - (FStar_Getopt.noshort, "log_types", (Const (Bool true)), - "Print types computed for data/val/let-bindings"); - (FStar_Getopt.noshort, "log_queries", (Const (Bool true)), - "Log the Z3 queries in several queries-*.smt2 files, as we go"); - (FStar_Getopt.noshort, "max_fuel", (IntStr "non-negative integer"), - "Number of unrolling of recursive functions to try at most (default 8)"); - (FStar_Getopt.noshort, "max_ifuel", (IntStr "non-negative integer"), - "Number of unrolling of inductive datatypes to try at most (default 2)"); - (FStar_Getopt.noshort, "MLish", (Const (Bool true)), - "Trigger various specializations for compiling the F* compiler itself (not meant for user code)"); - (FStar_Getopt.noshort, "no_default_includes", (Const (Bool true)), - "Ignore the default module search paths"); - (FStar_Getopt.noshort, "no_extract", - (Accumulated (PathStr "module name")), - "Deprecated: use --extract instead; Do not extract code from this module"); - (FStar_Getopt.noshort, "no_location_info", (Const (Bool true)), - "Suppress location information in the generated OCaml output (only relevant with --codegen OCaml)"); - (FStar_Getopt.noshort, "no_smt", (Const (Bool true)), - "Do not send any queries to the SMT solver, and fail on them instead"); - (FStar_Getopt.noshort, "normalize_pure_terms_for_extraction", - (Const (Bool true)), - "Extract top-level pure terms after normalizing them. This can lead to very large code, but can result in more partial evaluation and compile-time specialization."); - (FStar_Getopt.noshort, "odir", - (PostProcessed (pp_validate_dir, (PathStr "dir"))), - "Place output in directory dir"); - (FStar_Getopt.noshort, "prims", (PathStr "file"), ""); - (FStar_Getopt.noshort, "print_bound_var_types", (Const (Bool true)), - "Print the types of bound variables"); - (FStar_Getopt.noshort, "print_effect_args", (Const (Bool true)), - "Print inferred predicate transformers for all computation types"); - (FStar_Getopt.noshort, "print_expected_failures", (Const (Bool true)), - "Print the errors generated by declarations marked with expect_failure, useful for debugging error locations"); - (FStar_Getopt.noshort, "print_full_names", (Const (Bool true)), - "Print full names of variables"); - (FStar_Getopt.noshort, "print_implicits", (Const (Bool true)), - "Print implicit arguments"); - (FStar_Getopt.noshort, "print_universes", (Const (Bool true)), - "Print universes"); - (FStar_Getopt.noshort, "print_z3_statistics", (Const (Bool true)), - "Print Z3 statistics for each SMT query (details such as relevant modules, facts, etc. for each proof)"); - (FStar_Getopt.noshort, "prn", (Const (Bool true)), - "Print full names (deprecated; use --print_full_names instead)"); - (FStar_Getopt.noshort, "quake", - (PostProcessed - (((fun uu___ -> - match uu___ with - | String s -> - let uu___1 = interp_quake_arg s in - (match uu___1 with - | (min, max, k) -> - (set_option "quake_lo" (Int min); - set_option "quake_hi" (Int max); - set_option "quake_keep" (Bool k); - set_option "retry" (Bool false); - String s)) - | uu___1 -> failwith "impos")), - (SimpleStr "positive integer or pair of positive integers"))), - "Repeats SMT queries to check for robustness\n\t\t--quake N/M repeats each query checks that it succeeds at least N out of M times, aborting early if possible\n\t\t--quake N/M/k works as above, except it will unconditionally run M times\n\t\t--quake N is an alias for --quake N/N\n\t\t--quake N/k is an alias for --quake N/N/k\n\tUsing --quake disables --retry."); - (FStar_Getopt.noshort, "query_stats", (Const (Bool true)), - "Print SMT query statistics"); - (FStar_Getopt.noshort, "record_hints", (Const (Bool true)), - "Record a database of hints for efficient proof replay"); - (FStar_Getopt.noshort, "record_options", (Const (Bool true)), - "Record the state of options used to check each sigelt, useful for the `check_with` attribute and metaprogramming"); - (FStar_Getopt.noshort, "retry", - (PostProcessed - (((fun uu___ -> - match uu___ with - | Int i -> - (set_option "quake_lo" (Int Prims.int_one); - set_option "quake_hi" (Int i); - set_option "quake_keep" (Bool false); - set_option "retry" (Bool true); - Bool true) - | uu___1 -> failwith "impos")), (IntStr "positive integer"))), - "Retry each SMT query N times and succeed on the first try. Using --retry disables --quake."); - (FStar_Getopt.noshort, "reuse_hint_for", (SimpleStr "toplevel_name"), - "Optimistically, attempt using the recorded hint for toplevel_name (a top-level name in the current module) when trying to verify some other term 'g'"); - (FStar_Getopt.noshort, "report_assumes", (EnumStr ["warn"; "error"]), - "Report every use of an escape hatch, include assume, admit, etc."); - (FStar_Getopt.noshort, "silent", (Const (Bool true)), - "Disable all non-critical output"); - (FStar_Getopt.noshort, "smt", (PathStr "path"), - "Path to the Z3 SMT solver (we could eventually support other solvers)"); - (FStar_Getopt.noshort, "smtencoding.elim_box", BoolStr, - "Toggle a peephole optimization that eliminates redundant uses of boxing/unboxing in the SMT encoding (default 'false')"); - (FStar_Getopt.noshort, "smtencoding.nl_arith_repr", - (EnumStr ["native"; "wrapped"; "boxwrap"]), - "Control the representation of non-linear arithmetic functions in the SMT encoding:\n\t\ti.e., if 'boxwrap' use 'Prims.op_Multiply, Prims.op_Division, Prims.op_Modulus'; \n\t\tif 'native' use '*, div, mod';\n\t\tif 'wrapped' use '_mul, _div, _mod : Int*Int -> Int'; \n\t\t(default 'boxwrap')"); - (FStar_Getopt.noshort, "smtencoding.l_arith_repr", - (EnumStr ["native"; "boxwrap"]), - "Toggle the representation of linear arithmetic functions in the SMT encoding:\n\t\ti.e., if 'boxwrap', use 'Prims.op_Addition, Prims.op_Subtraction, Prims.op_Minus'; \n\t\tif 'native', use '+, -, -'; \n\t\t(default 'boxwrap')"); - (FStar_Getopt.noshort, "smtencoding.valid_intro", BoolStr, - "Include an axiom in the SMT encoding to introduce proof-irrelevance from a constructive proof"); - (FStar_Getopt.noshort, "smtencoding.valid_elim", BoolStr, - "Include an axiom in the SMT encoding to eliminate proof-irrelevance into the existence of a proof witness"); - (FStar_Getopt.noshort, "split_queries", (Const (Bool true)), - "Split SMT verification conditions into several separate queries, one per goal"); - (FStar_Getopt.noshort, "tactic_raw_binders", (Const (Bool true)), - "Do not use the lexical scope of tactics to improve binder names"); - (FStar_Getopt.noshort, "tactics_failhard", (Const (Bool true)), - "Do not recover from metaprogramming errors, and abort if one occurs"); - (FStar_Getopt.noshort, "tactics_info", (Const (Bool true)), - "Print some rough information on tactics, such as the time they take to run"); - (FStar_Getopt.noshort, "tactic_trace", (Const (Bool true)), - "Print a depth-indexed trace of tactic execution (Warning: very verbose)"); - (FStar_Getopt.noshort, "tactic_trace_d", (IntStr "positive_integer"), - "Trace tactics up to a certain binding depth"); - (FStar_Getopt.noshort, "__tactics_nbe", (Const (Bool true)), - "Use NBE to evaluate metaprograms (experimental)"); - (FStar_Getopt.noshort, "tcnorm", BoolStr, - "Attempt to normalize definitions marked as tcnorm (default 'true')"); - (FStar_Getopt.noshort, "timing", (Const (Bool true)), - "Print the time it takes to verify each top-level definition.\n\t\tThis is just an alias for an invocation of the profiler, so it may not work well if combined with --profile.\n\t\tIn particular, it implies --profile_group_by_decls."); - (FStar_Getopt.noshort, "trace_error", (Const (Bool true)), - "Don't print an error message; show an exception trace instead"); - (FStar_Getopt.noshort, "ugly", (Const (Bool true)), - "Emit output formatted for debugging"); - (FStar_Getopt.noshort, "unthrottle_inductives", (Const (Bool true)), - "Let the SMT solver unfold inductive types to arbitrary depths (may affect verifier performance)"); - (FStar_Getopt.noshort, "unsafe_tactic_exec", (Const (Bool true)), - "Allow tactics to run external processes. WARNING: checking an untrusted F* file while using this option can have disastrous effects."); - (FStar_Getopt.noshort, "use_eq_at_higher_order", (Const (Bool true)), - "Use equality constraints when comparing higher-order types (Temporary)"); - (FStar_Getopt.noshort, "use_hints", (Const (Bool true)), - "Use a previously recorded hints database for proof replay"); - (FStar_Getopt.noshort, "use_hint_hashes", (Const (Bool true)), - "Admit queries if their hash matches the hash recorded in the hints database"); - (FStar_Getopt.noshort, "use_native_tactics", (PathStr "path"), - "Use compiled tactics from path"); - (FStar_Getopt.noshort, "no_plugins", (Const (Bool true)), - "Do not run plugins natively and interpret them as usual instead"); - (FStar_Getopt.noshort, "no_tactics", (Const (Bool true)), - "Do not run the tactic engine before discharging a VC"); - (FStar_Getopt.noshort, "using_facts_from", - (ReverseAccumulated - (SimpleStr - "One or more space-separated occurrences of '[+|-]( * | namespace | fact id)'")), - "\n\t\tPrunes the context to include only the facts from the given namespace or fact id. \n\t\t\tFacts can be include or excluded using the [+|-] qualifier. \n\t\t\tFor example --using_facts_from '* -FStar.Reflection +FStar.Compiler.List -FStar.Compiler.List.Tot' will \n\t\t\t\tremove all facts from FStar.Compiler.List.Tot.*, \n\t\t\t\tretain all remaining facts from FStar.Compiler.List.*, \n\t\t\t\tremove all facts from FStar.Reflection.*, \n\t\t\t\tand retain all the rest.\n\t\tNote, the '+' is optional: --using_facts_from 'FStar.Compiler.List' is equivalent to --using_facts_from '+FStar.Compiler.List'. \n\t\tMultiple uses of this option accumulate, e.g., --using_facts_from A --using_facts_from B is interpreted as --using_facts_from A^B."); - (FStar_Getopt.noshort, "__temp_fast_implicits", (Const (Bool true)), - "Don't use this option yet"); - (118, "version", - (WithSideEffect - (((fun uu___ -> - display_version (); FStar_Compiler_Effect.exit Prims.int_zero)), - (Const (Bool true)))), "Display version number"); - (FStar_Getopt.noshort, "warn_default_effects", (Const (Bool true)), - "Warn when (a -> b) is desugared to (a -> Tot b)"); - (FStar_Getopt.noshort, "z3cliopt", - (ReverseAccumulated (SimpleStr "option")), "Z3 command line options"); - (FStar_Getopt.noshort, "z3smtopt", - (ReverseAccumulated (SimpleStr "option")), "Z3 options in smt2 format"); - (FStar_Getopt.noshort, "z3refresh", (Const (Bool true)), - "Restart Z3 after each query; useful for ensuring proof robustness"); - (FStar_Getopt.noshort, "z3rlimit", (IntStr "positive_integer"), - "Set the Z3 per-query resource limit (default 5 units, taking roughtly 5s)"); - (FStar_Getopt.noshort, "z3rlimit_factor", (IntStr "positive_integer"), - "Set the Z3 per-query resource limit multiplier. This is useful when, say, regenerating hints and you want to be more lax. (default 1)"); - (FStar_Getopt.noshort, "z3seed", (IntStr "positive_integer"), - "Set the Z3 random seed (default 0)"); - (FStar_Getopt.noshort, "__no_positivity", - (WithSideEffect - (((fun uu___ -> - if warn_unsafe - then option_warning_callback "__no_positivity" - else ())), (Const (Bool true)))), - "Don't check positivity of inductive types"); - (FStar_Getopt.noshort, "warn_error", (Accumulated (SimpleStr "")), - "The [-warn_error] option follows the OCaml syntax, namely:\n\t\t- [r] is a range of warnings (either a number [n], or a range [n..n])\n\t\t- [-r] silences range [r]\n\t\t- [+r] enables range [r]\n\t\t- [@r] makes range [r] fatal."); - (FStar_Getopt.noshort, "use_nbe", BoolStr, - "Use normalization by evaluation as the default normalization strategy (default 'false')"); - (FStar_Getopt.noshort, "use_nbe_for_extraction", BoolStr, - "Use normalization by evaluation for normalizing terms before extraction (default 'false')"); - (FStar_Getopt.noshort, "trivial_pre_for_unannotated_effectful_fns", - BoolStr, - "Enforce trivial preconditions for unannotated effectful functions (default 'true')"); - (FStar_Getopt.noshort, "__debug_embedding", - (WithSideEffect - (((fun uu___ -> - FStar_Compiler_Effect.op_Colon_Equals debug_embedding true)), - (Const (Bool true)))), - "Debug messages for embeddings/unembeddings of natively compiled terms"); - (FStar_Getopt.noshort, "eager_embedding", - (WithSideEffect - (((fun uu___ -> - FStar_Compiler_Effect.op_Colon_Equals eager_embedding true)), - (Const (Bool true)))), - "Eagerly embed and unembed terms to primitive operations and plugins: not recommended except for benchmarking"); - (FStar_Getopt.noshort, "profile_group_by_decl", (Const (Bool true)), - "Emit profiles grouped by declaration rather than by module"); - (FStar_Getopt.noshort, "profile_component", - (Accumulated - (SimpleStr - "One or more space-separated occurrences of '[+|-]( * | namespace | module | identifier)'")), - "\n\tSpecific source locations in the compiler are instrumented with profiling counters.\n\tPass `--profile_component FStar.TypeChecker` to enable all counters in the FStar.TypeChecker namespace.\n\tThis option is a module or namespace selector, like many other options (e.g., `--extract`)"); - (FStar_Getopt.noshort, "profile", - (Accumulated - (SimpleStr - "One or more space-separated occurrences of '[+|-]( * | namespace | module)'")), - "\n\tProfiling can be enabled when the compiler is processing a given set of source modules.\n\tPass `--profile FStar.Pervasives` to enable profiling when the compiler is processing any module in FStar.Pervasives.\n\tThis option is a module or namespace selector, like many other options (e.g., `--extract`)"); - (104, "help", - (WithSideEffect - (((fun uu___ -> - (let uu___2 = specs warn_unsafe in display_usage_aux uu___2); - FStar_Compiler_Effect.exit Prims.int_zero)), - (Const (Bool true)))), "Display this information")] -and (specs : Prims.bool -> FStar_Getopt.opt Prims.list) = - fun warn_unsafe -> - let uu___ = specs_with_types warn_unsafe in - FStar_Compiler_List.map - (fun uu___1 -> - match uu___1 with - | (short, long, typ, doc) -> - let uu___2 = - let uu___3 = arg_spec_of_opt_type long typ in - (short, long, uu___3, doc) in - mk_spec uu___2) uu___ -let (settable : Prims.string -> Prims.bool) = - fun uu___ -> - match uu___ with - | "abort_on" -> true - | "admit_except" -> true - | "admit_smt_queries" -> true - | "compat_pre_core" -> true - | "compat_pre_typed_indexed_effects" -> true - | "disallow_unification_guards" -> true - | "debug" -> true - | "debug_level" -> true - | "defensive" -> true - | "detail_errors" -> true - | "detail_hint_replay" -> true - | "eager_subtyping" -> true - | "error_contexts" -> true - | "hide_uvar_nums" -> true - | "hint_dir" -> true - | "hint_file" -> true - | "hint_info" -> true - | "fuel" -> true - | "ifuel" -> true - | "initial_fuel" -> true - | "initial_ifuel" -> true - | "ide_id_info_off" -> true - | "keep_query_captions" -> true - | "lax" -> true - | "load" -> true - | "load_cmxs" -> true - | "log_queries" -> true - | "log_types" -> true - | "max_fuel" -> true - | "max_ifuel" -> true - | "no_plugins" -> true - | "__no_positivity" -> true - | "normalize_pure_terms_for_extraction" -> true - | "no_smt" -> true - | "no_tactics" -> true - | "print_bound_var_types" -> true - | "print_effect_args" -> true - | "print_expected_failures" -> true - | "print_full_names" -> true - | "print_implicits" -> true - | "print_universes" -> true - | "print_z3_statistics" -> true - | "prn" -> true - | "quake_lo" -> true - | "quake_hi" -> true - | "quake_keep" -> true - | "quake" -> true - | "query_stats" -> true - | "record_options" -> true - | "retry" -> true - | "reuse_hint_for" -> true - | "report_assumes" -> true - | "silent" -> true - | "smtencoding.elim_box" -> true - | "smtencoding.l_arith_repr" -> true - | "smtencoding.nl_arith_repr" -> true - | "smtencoding.valid_intro" -> true - | "smtencoding.valid_elim" -> true - | "split_queries" -> true - | "tactic_raw_binders" -> true - | "tactics_failhard" -> true - | "tactics_info" -> true - | "__tactics_nbe" -> true - | "tactic_trace" -> true - | "tactic_trace_d" -> true - | "tcnorm" -> true - | "__temp_fast_implicits" -> true - | "timing" -> true - | "trace_error" -> true - | "ugly" -> true - | "unthrottle_inductives" -> true - | "use_eq_at_higher_order" -> true - | "using_facts_from" -> true - | "warn_error" -> true - | "z3cliopt" -> true - | "z3smtopt" -> true - | "z3refresh" -> true - | "z3rlimit" -> true - | "z3rlimit_factor" -> true - | "z3seed" -> true - | "trivial_pre_for_unannotated_effectful_fns" -> true - | "profile_group_by_decl" -> true - | "profile_component" -> true - | "profile" -> true - | uu___1 -> false -let (all_specs : FStar_Getopt.opt Prims.list) = specs true -let (all_specs_with_types : - (FStar_BaseTypes.char * Prims.string * opt_type * Prims.string) Prims.list) - = specs_with_types true -let (settable_specs : - (FStar_BaseTypes.char * Prims.string * unit FStar_Getopt.opt_variant * - Prims.string) Prims.list) - = - FStar_Compiler_Effect.op_Bar_Greater all_specs - (FStar_Compiler_List.filter - (fun uu___ -> - match uu___ with | (uu___1, x, uu___2, uu___3) -> settable x)) -let (uu___638 : - (((unit -> FStar_Getopt.parse_cmdline_res) -> unit) * - (unit -> FStar_Getopt.parse_cmdline_res))) - = - let callback = FStar_Compiler_Util.mk_ref FStar_Pervasives_Native.None in - let set1 f = - FStar_Compiler_Effect.op_Colon_Equals callback - (FStar_Pervasives_Native.Some f) in - let call uu___ = - let uu___1 = FStar_Compiler_Effect.op_Bang callback in - match uu___1 with - | FStar_Pervasives_Native.None -> - failwith "Error flags callback not yet set" - | FStar_Pervasives_Native.Some f -> f () in - (set1, call) -let (set_error_flags_callback_aux : - (unit -> FStar_Getopt.parse_cmdline_res) -> unit) = - match uu___638 with - | (set_error_flags_callback_aux1, set_error_flags) -> - set_error_flags_callback_aux1 -let (set_error_flags : unit -> FStar_Getopt.parse_cmdline_res) = - match uu___638 with - | (set_error_flags_callback_aux1, set_error_flags1) -> set_error_flags1 -let (set_error_flags_callback : - (unit -> FStar_Getopt.parse_cmdline_res) -> unit) = - set_error_flags_callback_aux -let (display_usage : unit -> unit) = fun uu___ -> display_usage_aux all_specs -let (fstar_bin_directory : Prims.string) = - FStar_Compiler_Util.get_exec_dir () -let (file_list_ : Prims.string Prims.list FStar_Compiler_Effect.ref) = - FStar_Compiler_Util.mk_ref [] -let rec (parse_filename_arg : - FStar_Getopt.opt Prims.list -> - Prims.bool -> Prims.string -> FStar_Getopt.parse_cmdline_res) - = - fun specs1 -> - fun enable_filenames -> - fun arg -> - if FStar_Compiler_Util.starts_with arg "@" - then - let filename = FStar_Compiler_Util.substring_from arg Prims.int_one in - let lines = FStar_Compiler_Util.file_get_lines filename in - FStar_Getopt.parse_list specs1 - (parse_filename_arg specs1 enable_filenames) lines - else - (if enable_filenames - then - (let uu___2 = - let uu___3 = FStar_Compiler_Effect.op_Bang file_list_ in - FStar_Compiler_List.op_At uu___3 [arg] in - FStar_Compiler_Effect.op_Colon_Equals file_list_ uu___2) - else (); - FStar_Getopt.Success) -let (parse_cmd_line : - unit -> (FStar_Getopt.parse_cmdline_res * Prims.string Prims.list)) = - fun uu___ -> - let res = - FStar_Getopt.parse_cmdline all_specs - (parse_filename_arg all_specs true) in - let res1 = if res = FStar_Getopt.Success then set_error_flags () else res in - let uu___1 = - let uu___2 = FStar_Compiler_Effect.op_Bang file_list_ in - FStar_Compiler_List.map FStar_Common.try_convert_file_name_to_mixed - uu___2 in - (res1, uu___1) -let (file_list : unit -> Prims.string Prims.list) = - fun uu___ -> FStar_Compiler_Effect.op_Bang file_list_ -let (restore_cmd_line_options : Prims.bool -> FStar_Getopt.parse_cmdline_res) - = - fun should_clear -> - let old_verify_module = get_verify_module () in - if should_clear then clear () else init (); - (let specs1 = specs false in - let r = - FStar_Getopt.parse_cmdline specs1 (parse_filename_arg specs1 false) in - (let uu___2 = - let uu___3 = - let uu___4 = - FStar_Compiler_List.map (fun uu___5 -> String uu___5) - old_verify_module in - List uu___4 in - ("verify_module", uu___3) in - set_option' uu___2); - r) -let (module_name_of_file_name : Prims.string -> Prims.string) = - fun f -> - let f1 = FStar_Compiler_Util.basename f in - let f2 = - let uu___ = - let uu___1 = - let uu___2 = - let uu___3 = FStar_Compiler_Util.get_file_extension f1 in - FStar_String.length uu___3 in - (FStar_String.length f1) - uu___2 in - uu___1 - Prims.int_one in - FStar_String.substring f1 Prims.int_zero uu___ in - FStar_String.lowercase f2 -let (should_check : Prims.string -> Prims.bool) = - fun m -> - let l = get_verify_module () in - FStar_Compiler_List.contains (FStar_String.lowercase m) l -let (should_verify : Prims.string -> Prims.bool) = - fun m -> - (let uu___ = get_lax () in Prims.op_Negation uu___) && (should_check m) -let (should_check_file : Prims.string -> Prims.bool) = - fun fn -> let uu___ = module_name_of_file_name fn in should_check uu___ -let (should_verify_file : Prims.string -> Prims.bool) = - fun fn -> let uu___ = module_name_of_file_name fn in should_verify uu___ -let (module_name_eq : Prims.string -> Prims.string -> Prims.bool) = - fun m1 -> - fun m2 -> (FStar_String.lowercase m1) = (FStar_String.lowercase m2) -let (should_print_message : Prims.string -> Prims.bool) = - fun m -> - let uu___ = should_verify m in if uu___ then m <> "Prims" else false -let (include_path : unit -> Prims.string Prims.list) = - fun uu___ -> - let cache_dir = - let uu___1 = get_cache_dir () in - match uu___1 with - | FStar_Pervasives_Native.None -> [] - | FStar_Pervasives_Native.Some c -> [c] in - let uu___1 = get_no_default_includes () in - if uu___1 - then - let uu___2 = get_include () in - FStar_Compiler_List.op_At cache_dir uu___2 - else - (let lib_paths = - let uu___3 = - FStar_Compiler_Util.expand_environment_variable "FSTAR_LIB" in - match uu___3 with - | FStar_Pervasives_Native.None -> - let fstar_home = FStar_String.op_Hat fstar_bin_directory "/.." in - let defs = universe_include_path_base_dirs in - let uu___4 = - FStar_Compiler_Effect.op_Bar_Greater defs - (FStar_Compiler_List.map - (fun x -> FStar_String.op_Hat fstar_home x)) in - FStar_Compiler_Effect.op_Bar_Greater uu___4 - (FStar_Compiler_List.filter FStar_Compiler_Util.file_exists) - | FStar_Pervasives_Native.Some s -> [s] in - let uu___3 = - let uu___4 = - let uu___5 = get_include () in - FStar_Compiler_List.op_At uu___5 ["."] in - FStar_Compiler_List.op_At lib_paths uu___4 in - FStar_Compiler_List.op_At cache_dir uu___3) -let (find_file : Prims.string -> Prims.string FStar_Pervasives_Native.option) - = - let file_map = FStar_Compiler_Util.smap_create (Prims.of_int (100)) in - fun filename -> - let uu___ = FStar_Compiler_Util.smap_try_find file_map filename in - match uu___ with - | FStar_Pervasives_Native.Some f -> f - | FStar_Pervasives_Native.None -> - let result = - try - (fun uu___1 -> - match () with - | () -> - let uu___2 = FStar_Compiler_Util.is_path_absolute filename in - if uu___2 - then - (if FStar_Compiler_Util.file_exists filename - then FStar_Pervasives_Native.Some filename - else FStar_Pervasives_Native.None) - else - (let uu___4 = - let uu___5 = include_path () in - FStar_Compiler_List.rev uu___5 in - FStar_Compiler_Util.find_map uu___4 - (fun p -> - let path = - if p = "." - then filename - else FStar_Compiler_Util.join_paths p filename in - if FStar_Compiler_Util.file_exists path - then FStar_Pervasives_Native.Some path - else FStar_Pervasives_Native.None))) () - with | uu___1 -> FStar_Pervasives_Native.None in - (if FStar_Compiler_Option.isSome result - then FStar_Compiler_Util.smap_add file_map filename result - else (); - result) -let (prims : unit -> Prims.string) = - fun uu___ -> - let uu___1 = get_prims () in - match uu___1 with - | FStar_Pervasives_Native.None -> - let filename = "prims.fst" in - let uu___2 = find_file filename in - (match uu___2 with - | FStar_Pervasives_Native.Some result -> result - | FStar_Pervasives_Native.None -> - let uu___3 = - FStar_Compiler_Util.format1 - "unable to find required file \"%s\" in the module search path.\n" - filename in - failwith uu___3) - | FStar_Pervasives_Native.Some x -> x -let (prims_basename : unit -> Prims.string) = - fun uu___ -> let uu___1 = prims () in FStar_Compiler_Util.basename uu___1 -let (pervasives : unit -> Prims.string) = - fun uu___ -> - let filename = "FStar.Pervasives.fsti" in - let uu___1 = find_file filename in - match uu___1 with - | FStar_Pervasives_Native.Some result -> result - | FStar_Pervasives_Native.None -> - let uu___2 = - FStar_Compiler_Util.format1 - "unable to find required file \"%s\" in the module search path.\n" - filename in - failwith uu___2 -let (pervasives_basename : unit -> Prims.string) = - fun uu___ -> - let uu___1 = pervasives () in FStar_Compiler_Util.basename uu___1 -let (pervasives_native_basename : unit -> Prims.string) = - fun uu___ -> - let filename = "FStar.Pervasives.Native.fst" in - let uu___1 = find_file filename in - match uu___1 with - | FStar_Pervasives_Native.Some result -> - FStar_Compiler_Util.basename result - | FStar_Pervasives_Native.None -> - let uu___2 = - FStar_Compiler_Util.format1 - "unable to find required file \"%s\" in the module search path.\n" - filename in - failwith uu___2 -let (prepend_output_dir : Prims.string -> Prims.string) = - fun fname -> - let uu___ = get_odir () in - match uu___ with - | FStar_Pervasives_Native.None -> fname - | FStar_Pervasives_Native.Some x -> - FStar_Compiler_Util.join_paths x fname -let (prepend_cache_dir : Prims.string -> Prims.string) = - fun fpath -> - let uu___ = get_cache_dir () in - match uu___ with - | FStar_Pervasives_Native.None -> fpath - | FStar_Pervasives_Native.Some x -> - let uu___1 = FStar_Compiler_Util.basename fpath in - FStar_Compiler_Util.join_paths x uu___1 -let (path_of_text : Prims.string -> Prims.string Prims.list) = - fun text -> FStar_String.split [46] text -let (parse_settings : - Prims.string Prims.list -> - (Prims.string Prims.list * Prims.bool) Prims.list) - = - fun ns -> - let cache = FStar_Compiler_Util.smap_create (Prims.of_int (31)) in - let with_cache f s = - let uu___ = FStar_Compiler_Util.smap_try_find cache s in - match uu___ with - | FStar_Pervasives_Native.Some s1 -> s1 - | FStar_Pervasives_Native.None -> - let res = f s in (FStar_Compiler_Util.smap_add cache s res; res) in - let parse_one_setting s = - if s = "*" - then ([], true) - else - if s = "-*" - then ([], false) - else - if FStar_Compiler_Util.starts_with s "-" - then - (let path = - let uu___2 = - FStar_Compiler_Util.substring_from s Prims.int_one in - path_of_text uu___2 in - (path, false)) - else - (let s1 = - if FStar_Compiler_Util.starts_with s "+" - then FStar_Compiler_Util.substring_from s Prims.int_one - else s in - ((path_of_text s1), true)) in - let uu___ = - FStar_Compiler_Effect.op_Bar_Greater ns - (FStar_Compiler_List.collect - (fun s -> - let s1 = FStar_Compiler_Util.trim_string s in - if s1 = "" - then [] - else - with_cache - (fun s2 -> - let s3 = FStar_Compiler_Util.replace_char s2 32 44 in - let uu___2 = - let uu___3 = - FStar_Compiler_Effect.op_Bar_Greater - (FStar_Compiler_Util.splitlines s3) - (FStar_Compiler_List.concatMap - (fun s4 -> FStar_Compiler_Util.split s4 ",")) in - FStar_Compiler_Effect.op_Bar_Greater uu___3 - (FStar_Compiler_List.filter (fun s4 -> s4 <> "")) in - FStar_Compiler_Effect.op_Bar_Greater uu___2 - (FStar_Compiler_List.map parse_one_setting)) s1)) in - FStar_Compiler_Effect.op_Bar_Greater uu___ FStar_Compiler_List.rev -let (__temp_fast_implicits : unit -> Prims.bool) = - fun uu___ -> lookup_opt "__temp_fast_implicits" as_bool -let (admit_smt_queries : unit -> Prims.bool) = - fun uu___ -> get_admit_smt_queries () -let (admit_except : unit -> Prims.string FStar_Pervasives_Native.option) = - fun uu___ -> get_admit_except () -let (compat_pre_core_should_register : unit -> Prims.bool) = - fun uu___ -> - let uu___1 = get_compat_pre_core () in - match uu___1 with - | FStar_Pervasives_Native.Some uu___2 when uu___2 = Prims.int_zero -> - false - | uu___2 -> true -let (compat_pre_core_should_check : unit -> Prims.bool) = - fun uu___ -> - let uu___1 = get_compat_pre_core () in - match uu___1 with - | FStar_Pervasives_Native.Some uu___2 when uu___2 = Prims.int_zero -> - false - | FStar_Pervasives_Native.Some uu___2 when uu___2 = Prims.int_one -> - false - | uu___2 -> true -let (compat_pre_core_set : unit -> Prims.bool) = - fun uu___ -> - let uu___1 = get_compat_pre_core () in - match uu___1 with - | FStar_Pervasives_Native.None -> false - | uu___2 -> true -let (compat_pre_typed_indexed_effects : unit -> Prims.bool) = - fun uu___ -> get_compat_pre_typed_indexed_effects () -let (disallow_unification_guards : unit -> Prims.bool) = - fun uu___ -> get_disallow_unification_guards () -let (cache_checked_modules : unit -> Prims.bool) = - fun uu___ -> get_cache_checked_modules () -let (cache_off : unit -> Prims.bool) = fun uu___ -> get_cache_off () -let (print_cache_version : unit -> Prims.bool) = - fun uu___ -> get_print_cache_version () -let (cmi : unit -> Prims.bool) = fun uu___ -> get_cmi () -type codegen_t = - | OCaml - | FSharp - | Krml - | Plugin -let (uu___is_OCaml : codegen_t -> Prims.bool) = - fun projectee -> match projectee with | OCaml -> true | uu___ -> false -let (uu___is_FSharp : codegen_t -> Prims.bool) = - fun projectee -> match projectee with | FSharp -> true | uu___ -> false -let (uu___is_Krml : codegen_t -> Prims.bool) = - fun projectee -> match projectee with | Krml -> true | uu___ -> false -let (uu___is_Plugin : codegen_t -> Prims.bool) = - fun projectee -> match projectee with | Plugin -> true | uu___ -> false -let (parse_codegen : - Prims.string -> codegen_t FStar_Pervasives_Native.option) = - fun uu___ -> - match uu___ with - | "OCaml" -> FStar_Pervasives_Native.Some OCaml - | "FSharp" -> FStar_Pervasives_Native.Some FSharp - | "krml" -> FStar_Pervasives_Native.Some Krml - | "Plugin" -> FStar_Pervasives_Native.Some Plugin - | uu___1 -> FStar_Pervasives_Native.None -let (print_codegen : codegen_t -> Prims.string) = - fun uu___ -> - match uu___ with - | OCaml -> "OCaml" - | FSharp -> "FSharp" - | Krml -> "krml" - | Plugin -> "Plugin" -let (codegen : unit -> codegen_t FStar_Pervasives_Native.option) = - fun uu___ -> - let uu___1 = get_codegen () in - FStar_Compiler_Util.map_opt uu___1 - (fun s -> - let uu___2 = parse_codegen s in - FStar_Compiler_Effect.op_Bar_Greater uu___2 FStar_Compiler_Util.must) -let (codegen_libs : unit -> Prims.string Prims.list Prims.list) = - fun uu___ -> - let uu___1 = get_codegen_lib () in - FStar_Compiler_Effect.op_Bar_Greater uu___1 - (FStar_Compiler_List.map (fun x -> FStar_Compiler_Util.split x ".")) -let (debug_any : unit -> Prims.bool) = - fun uu___ -> let uu___1 = get_debug () in uu___1 <> [] -let (debug_module : Prims.string -> Prims.bool) = - fun modul -> - let uu___ = get_debug () in - FStar_Compiler_Effect.op_Bar_Greater uu___ - (FStar_Compiler_List.existsb (module_name_eq modul)) -let (debug_at_level_no_module : debug_level_t -> Prims.bool) = - fun level -> debug_level_geq level -let (debug_at_level : Prims.string -> debug_level_t -> Prims.bool) = - fun modul -> - fun level -> (debug_module modul) && (debug_at_level_no_module level) -let (profile_group_by_decls : unit -> Prims.bool) = - fun uu___ -> get_profile_group_by_decl () -let (defensive : unit -> Prims.bool) = - fun uu___ -> let uu___1 = get_defensive () in uu___1 <> "no" -let (defensive_error : unit -> Prims.bool) = - fun uu___ -> let uu___1 = get_defensive () in uu___1 = "error" -let (defensive_abort : unit -> Prims.bool) = - fun uu___ -> let uu___1 = get_defensive () in uu___1 = "abort" -let (dep : unit -> Prims.string FStar_Pervasives_Native.option) = - fun uu___ -> get_dep () -let (detail_errors : unit -> Prims.bool) = fun uu___ -> get_detail_errors () -let (detail_hint_replay : unit -> Prims.bool) = - fun uu___ -> get_detail_hint_replay () -let (dump_module : Prims.string -> Prims.bool) = - fun s -> - let uu___ = get_dump_module () in - FStar_Compiler_Effect.op_Bar_Greater uu___ - (FStar_Compiler_List.existsb (module_name_eq s)) -let (eager_subtyping : unit -> Prims.bool) = - fun uu___ -> get_eager_subtyping () -let (error_contexts : unit -> Prims.bool) = - fun uu___ -> get_error_contexts () -let (expose_interfaces : unit -> Prims.bool) = - fun uu___ -> get_expose_interfaces () -let (force : unit -> Prims.bool) = fun uu___ -> get_force () -let (full_context_dependency : unit -> Prims.bool) = fun uu___ -> true -let (hide_uvar_nums : unit -> Prims.bool) = - fun uu___ -> get_hide_uvar_nums () -let (hint_info : unit -> Prims.bool) = - fun uu___ -> (get_hint_info ()) || (get_query_stats ()) -let (hint_dir : unit -> Prims.string FStar_Pervasives_Native.option) = - fun uu___ -> get_hint_dir () -let (hint_file : unit -> Prims.string FStar_Pervasives_Native.option) = - fun uu___ -> get_hint_file () -let (hint_file_for_src : Prims.string -> Prims.string) = - fun src_filename -> - let uu___ = hint_file () in - match uu___ with - | FStar_Pervasives_Native.Some fn -> fn - | FStar_Pervasives_Native.None -> - let file_name = - let uu___1 = hint_dir () in - match uu___1 with - | FStar_Pervasives_Native.Some dir -> - let uu___2 = FStar_Compiler_Util.basename src_filename in - FStar_Compiler_Util.concat_dir_filename dir uu___2 - | uu___2 -> src_filename in - FStar_Compiler_Util.format1 "%s.hints" file_name -let (ide : unit -> Prims.bool) = fun uu___ -> get_ide () -let (ide_id_info_off : unit -> Prims.bool) = - fun uu___ -> get_ide_id_info_off () -let (print : unit -> Prims.bool) = fun uu___ -> get_print () -let (print_in_place : unit -> Prims.bool) = - fun uu___ -> get_print_in_place () -let (initial_fuel : unit -> Prims.int) = - fun uu___ -> - let uu___1 = get_initial_fuel () in - let uu___2 = get_max_fuel () in Prims.min uu___1 uu___2 -let (initial_ifuel : unit -> Prims.int) = - fun uu___ -> - let uu___1 = get_initial_ifuel () in - let uu___2 = get_max_ifuel () in Prims.min uu___1 uu___2 -let (interactive : unit -> Prims.bool) = - fun uu___ -> ((get_in ()) || (get_ide ())) || (get_lsp ()) -let (lax : unit -> Prims.bool) = fun uu___ -> get_lax () -let (load : unit -> Prims.string Prims.list) = fun uu___ -> get_load () -let (load_cmxs : unit -> Prims.string Prims.list) = - fun uu___ -> get_load_cmxs () -let (legacy_interactive : unit -> Prims.bool) = fun uu___ -> get_in () -let (lsp_server : unit -> Prims.bool) = fun uu___ -> get_lsp () -let (log_queries : unit -> Prims.bool) = fun uu___ -> get_log_queries () -let (keep_query_captions : unit -> Prims.bool) = - fun uu___ -> (log_queries ()) && (get_keep_query_captions ()) -let (log_types : unit -> Prims.bool) = fun uu___ -> get_log_types () -let (max_fuel : unit -> Prims.int) = fun uu___ -> get_max_fuel () -let (max_ifuel : unit -> Prims.int) = fun uu___ -> get_max_ifuel () -let (ml_ish : unit -> Prims.bool) = fun uu___ -> get_MLish () -let (set_ml_ish : unit -> unit) = fun uu___ -> set_option "MLish" (Bool true) -let (no_default_includes : unit -> Prims.bool) = - fun uu___ -> get_no_default_includes () -let (no_extract : Prims.string -> Prims.bool) = - fun s -> - let uu___ = get_no_extract () in - FStar_Compiler_Effect.op_Bar_Greater uu___ - (FStar_Compiler_List.existsb (module_name_eq s)) -let (normalize_pure_terms_for_extraction : unit -> Prims.bool) = - fun uu___ -> get_normalize_pure_terms_for_extraction () -let (no_location_info : unit -> Prims.bool) = - fun uu___ -> get_no_location_info () -let (no_plugins : unit -> Prims.bool) = fun uu___ -> get_no_plugins () -let (no_smt : unit -> Prims.bool) = fun uu___ -> get_no_smt () -let (output_dir : unit -> Prims.string FStar_Pervasives_Native.option) = - fun uu___ -> get_odir () -let (ugly : unit -> Prims.bool) = fun uu___ -> get_ugly () -let (print_bound_var_types : unit -> Prims.bool) = - fun uu___ -> get_print_bound_var_types () -let (print_effect_args : unit -> Prims.bool) = - fun uu___ -> get_print_effect_args () -let (print_expected_failures : unit -> Prims.bool) = - fun uu___ -> get_print_expected_failures () -let (print_implicits : unit -> Prims.bool) = - fun uu___ -> get_print_implicits () -let (print_real_names : unit -> Prims.bool) = - fun uu___ -> (get_prn ()) || (get_print_full_names ()) -let (print_universes : unit -> Prims.bool) = - fun uu___ -> get_print_universes () -let (print_z3_statistics : unit -> Prims.bool) = - fun uu___ -> get_print_z3_statistics () -let (quake_lo : unit -> Prims.int) = fun uu___ -> get_quake_lo () -let (quake_hi : unit -> Prims.int) = fun uu___ -> get_quake_hi () -let (quake_keep : unit -> Prims.bool) = fun uu___ -> get_quake_keep () -let (query_stats : unit -> Prims.bool) = fun uu___ -> get_query_stats () -let (record_hints : unit -> Prims.bool) = fun uu___ -> get_record_hints () -let (record_options : unit -> Prims.bool) = - fun uu___ -> get_record_options () -let (retry : unit -> Prims.bool) = fun uu___ -> get_retry () -let (reuse_hint_for : unit -> Prims.string FStar_Pervasives_Native.option) = - fun uu___ -> get_reuse_hint_for () -let (report_assumes : unit -> Prims.string FStar_Pervasives_Native.option) = - fun uu___ -> get_report_assumes () -let (silent : unit -> Prims.bool) = fun uu___ -> get_silent () -let (smtencoding_elim_box : unit -> Prims.bool) = - fun uu___ -> get_smtencoding_elim_box () -let (smtencoding_nl_arith_native : unit -> Prims.bool) = - fun uu___ -> - let uu___1 = get_smtencoding_nl_arith_repr () in uu___1 = "native" -let (smtencoding_nl_arith_wrapped : unit -> Prims.bool) = - fun uu___ -> - let uu___1 = get_smtencoding_nl_arith_repr () in uu___1 = "wrapped" -let (smtencoding_nl_arith_default : unit -> Prims.bool) = - fun uu___ -> - let uu___1 = get_smtencoding_nl_arith_repr () in uu___1 = "boxwrap" -let (smtencoding_l_arith_native : unit -> Prims.bool) = - fun uu___ -> - let uu___1 = get_smtencoding_l_arith_repr () in uu___1 = "native" -let (smtencoding_l_arith_default : unit -> Prims.bool) = - fun uu___ -> - let uu___1 = get_smtencoding_l_arith_repr () in uu___1 = "boxwrap" -let (smtencoding_valid_intro : unit -> Prims.bool) = - fun uu___ -> get_smtencoding_valid_intro () -let (smtencoding_valid_elim : unit -> Prims.bool) = - fun uu___ -> get_smtencoding_valid_elim () -let (split_queries : unit -> Prims.bool) = fun uu___ -> get_split_queries () -let (tactic_raw_binders : unit -> Prims.bool) = - fun uu___ -> get_tactic_raw_binders () -let (tactics_failhard : unit -> Prims.bool) = - fun uu___ -> get_tactics_failhard () -let (tactics_info : unit -> Prims.bool) = fun uu___ -> get_tactics_info () -let (tactic_trace : unit -> Prims.bool) = fun uu___ -> get_tactic_trace () -let (tactic_trace_d : unit -> Prims.int) = fun uu___ -> get_tactic_trace_d () -let (tactics_nbe : unit -> Prims.bool) = fun uu___ -> get_tactics_nbe () -let (tcnorm : unit -> Prims.bool) = fun uu___ -> get_tcnorm () -let (timing : unit -> Prims.bool) = fun uu___ -> get_timing () -let (trace_error : unit -> Prims.bool) = fun uu___ -> get_trace_error () -let (unthrottle_inductives : unit -> Prims.bool) = - fun uu___ -> get_unthrottle_inductives () -let (unsafe_tactic_exec : unit -> Prims.bool) = - fun uu___ -> get_unsafe_tactic_exec () -let (use_eq_at_higher_order : unit -> Prims.bool) = - fun uu___ -> get_use_eq_at_higher_order () -let (use_hints : unit -> Prims.bool) = fun uu___ -> get_use_hints () -let (use_hint_hashes : unit -> Prims.bool) = - fun uu___ -> get_use_hint_hashes () -let (use_native_tactics : - unit -> Prims.string FStar_Pervasives_Native.option) = - fun uu___ -> get_use_native_tactics () -let (use_tactics : unit -> Prims.bool) = - fun uu___ -> let uu___1 = get_no_tactics () in Prims.op_Negation uu___1 -let (using_facts_from : - unit -> (Prims.string Prims.list * Prims.bool) Prims.list) = - fun uu___ -> - let uu___1 = get_using_facts_from () in - match uu___1 with - | FStar_Pervasives_Native.None -> [([], true)] - | FStar_Pervasives_Native.Some ns -> parse_settings ns -let (warn_default_effects : unit -> Prims.bool) = - fun uu___ -> get_warn_default_effects () -let (warn_error : unit -> Prims.string) = - fun uu___ -> - let uu___1 = get_warn_error () in FStar_String.concat " " uu___1 -let (z3_exe : unit -> Prims.string) = - fun uu___ -> - let uu___1 = get_smt () in - match uu___1 with - | FStar_Pervasives_Native.None -> FStar_Platform.exe "z3" - | FStar_Pervasives_Native.Some s -> s -let (z3_cliopt : unit -> Prims.string Prims.list) = - fun uu___ -> get_z3cliopt () -let (z3_smtopt : unit -> Prims.string Prims.list) = - fun uu___ -> get_z3smtopt () -let (z3_refresh : unit -> Prims.bool) = fun uu___ -> get_z3refresh () -let (z3_rlimit : unit -> Prims.int) = fun uu___ -> get_z3rlimit () -let (z3_rlimit_factor : unit -> Prims.int) = - fun uu___ -> get_z3rlimit_factor () -let (z3_seed : unit -> Prims.int) = fun uu___ -> get_z3seed () -let (no_positivity : unit -> Prims.bool) = fun uu___ -> get_no_positivity () -let (use_nbe : unit -> Prims.bool) = fun uu___ -> get_use_nbe () -let (use_nbe_for_extraction : unit -> Prims.bool) = - fun uu___ -> get_use_nbe_for_extraction () -let (trivial_pre_for_unannotated_effectful_fns : unit -> Prims.bool) = - fun uu___ -> get_trivial_pre_for_unannotated_effectful_fns () -let with_saved_options : 'a . (unit -> 'a) -> 'a = - fun f -> - let uu___ = let uu___1 = trace_error () in Prims.op_Negation uu___1 in - if uu___ - then - (push (); - (let r = - try - (fun uu___2 -> - match () with - | () -> let uu___3 = f () in FStar_Pervasives.Inr uu___3) () - with | uu___2 -> FStar_Pervasives.Inl uu___2 in - pop (); - (match r with - | FStar_Pervasives.Inr v -> v - | FStar_Pervasives.Inl ex -> FStar_Compiler_Effect.raise ex))) - else (push (); (let retv = f () in pop (); retv)) -let (module_matches_namespace_filter : - Prims.string -> Prims.string Prims.list -> Prims.bool) = - fun m -> - fun filter -> - let m1 = FStar_String.lowercase m in - let setting = parse_settings filter in - let m_components = path_of_text m1 in - let rec matches_path m_components1 path = - match (m_components1, path) with - | (uu___, []) -> true - | (m2::ms, p::ps) -> - (m2 = (FStar_String.lowercase p)) && (matches_path ms ps) - | uu___ -> false in - let uu___ = - FStar_Compiler_Effect.op_Bar_Greater setting - (FStar_Compiler_Util.try_find - (fun uu___1 -> - match uu___1 with - | (path, uu___2) -> matches_path m_components path)) in - match uu___ with - | FStar_Pervasives_Native.None -> false - | FStar_Pervasives_Native.Some (uu___1, flag) -> flag -let (matches_namespace_filter_opt : - Prims.string -> - Prims.string Prims.list FStar_Pervasives_Native.option -> Prims.bool) - = - fun m -> - fun uu___ -> - match uu___ with - | FStar_Pervasives_Native.None -> false - | FStar_Pervasives_Native.Some filter -> - module_matches_namespace_filter m filter -type parsed_extract_setting = - { - target_specific_settings: (codegen_t * Prims.string) Prims.list ; - default_settings: Prims.string FStar_Pervasives_Native.option } -let (__proj__Mkparsed_extract_setting__item__target_specific_settings : - parsed_extract_setting -> (codegen_t * Prims.string) Prims.list) = - fun projectee -> - match projectee with - | { target_specific_settings; default_settings;_} -> - target_specific_settings -let (__proj__Mkparsed_extract_setting__item__default_settings : - parsed_extract_setting -> Prims.string FStar_Pervasives_Native.option) = - fun projectee -> - match projectee with - | { target_specific_settings; default_settings;_} -> default_settings -let (print_pes : parsed_extract_setting -> Prims.string) = - fun pes -> - let uu___ = - let uu___1 = - FStar_Compiler_List.map - (fun uu___2 -> - match uu___2 with - | (tgt, s) -> - FStar_Compiler_Util.format2 "(%s, %s)" (print_codegen tgt) s) - pes.target_specific_settings in - FStar_Compiler_Effect.op_Bar_Greater uu___1 (FStar_String.concat "; ") in - FStar_Compiler_Util.format2 - "{ target_specific_settings = %s;\n\t\n default_settings = %s }" - uu___ - (match pes.default_settings with - | FStar_Pervasives_Native.None -> "None" - | FStar_Pervasives_Native.Some s -> s) -let (find_setting_for_target : - codegen_t -> - (codegen_t * Prims.string) Prims.list -> - Prims.string FStar_Pervasives_Native.option) - = - fun tgt -> - fun s -> - let uu___ = - FStar_Compiler_Util.try_find - (fun uu___1 -> match uu___1 with | (x, uu___2) -> x = tgt) s in - match uu___ with - | FStar_Pervasives_Native.Some (uu___1, s1) -> - FStar_Pervasives_Native.Some s1 - | uu___1 -> FStar_Pervasives_Native.None -let (extract_settings : - unit -> parsed_extract_setting FStar_Pervasives_Native.option) = - let memo = FStar_Compiler_Util.mk_ref (FStar_Pervasives_Native.None, false) in - let merge_parsed_extract_settings p0 p1 = - let merge_setting s0 s1 = - match (s0, s1) with - | (FStar_Pervasives_Native.None, FStar_Pervasives_Native.None) -> - FStar_Pervasives_Native.None - | (FStar_Pervasives_Native.Some p, FStar_Pervasives_Native.None) -> - FStar_Pervasives_Native.Some p - | (FStar_Pervasives_Native.None, FStar_Pervasives_Native.Some p) -> - FStar_Pervasives_Native.Some p - | (FStar_Pervasives_Native.Some p01, FStar_Pervasives_Native.Some p11) - -> - let uu___ = - let uu___1 = FStar_String.op_Hat "," p11 in - FStar_String.op_Hat p01 uu___1 in - FStar_Pervasives_Native.Some uu___ in - let merge_target tgt = - let uu___ = - let uu___1 = find_setting_for_target tgt p0.target_specific_settings in - let uu___2 = find_setting_for_target tgt p1.target_specific_settings in - merge_setting uu___1 uu___2 in - match uu___ with - | FStar_Pervasives_Native.None -> [] - | FStar_Pervasives_Native.Some x -> [(tgt, x)] in - let uu___ = - FStar_Compiler_List.collect merge_target [OCaml; FSharp; Krml; Plugin] in - let uu___1 = merge_setting p0.default_settings p1.default_settings in - { target_specific_settings = uu___; default_settings = uu___1 } in - fun uu___ -> - let uu___1 = FStar_Compiler_Effect.op_Bang memo in - match uu___1 with - | (result, set1) -> - let fail msg = - display_usage (); - (let uu___3 = - FStar_Compiler_Util.format1 - "Could not parse '%s' passed to the --extract option" msg in - failwith uu___3) in - if set1 - then result - else - (let uu___3 = get_extract () in - match uu___3 with - | FStar_Pervasives_Native.None -> - (FStar_Compiler_Effect.op_Colon_Equals memo - (FStar_Pervasives_Native.None, true); - FStar_Pervasives_Native.None) - | FStar_Pervasives_Native.Some extract_settings1 -> - let parse_one_setting extract_setting = - let tgt_specific_settings = - FStar_Compiler_Util.split extract_setting ";" in - let split_one t_setting = - match FStar_Compiler_Util.split t_setting ":" with - | default_setting::[] -> - FStar_Pervasives.Inr - (FStar_Compiler_Util.trim_string default_setting) - | target::setting::[] -> - let target1 = FStar_Compiler_Util.trim_string target in - let uu___4 = parse_codegen target1 in - (match uu___4 with - | FStar_Pervasives_Native.None -> fail target1 - | FStar_Pervasives_Native.Some tgt -> - FStar_Pervasives.Inl - (tgt, - (FStar_Compiler_Util.trim_string setting)) - | uu___5 -> fail t_setting) in - let settings = - FStar_Compiler_List.map split_one tgt_specific_settings in - let fail_duplicate msg tgt = - display_usage (); - (let uu___5 = - FStar_Compiler_Util.format2 - "Could not parse '%s'; multiple setting for %s target" - msg tgt in - failwith uu___5) in - let pes = - FStar_Compiler_List.fold_right - (fun setting -> - fun out -> - match setting with - | FStar_Pervasives.Inr def -> - (match out.default_settings with - | FStar_Pervasives_Native.None -> - { - target_specific_settings = - (out.target_specific_settings); - default_settings = - (FStar_Pervasives_Native.Some def) - } - | FStar_Pervasives_Native.Some uu___4 -> - fail_duplicate def "default") - | FStar_Pervasives.Inl (target, setting1) -> - let uu___4 = - FStar_Compiler_Util.try_find - (fun uu___5 -> - match uu___5 with - | (x, uu___6) -> x = target) - out.target_specific_settings in - (match uu___4 with - | FStar_Pervasives_Native.None -> - { - target_specific_settings = - ((target, setting1) :: - (out.target_specific_settings)); - default_settings = - (out.default_settings) - } - | FStar_Pervasives_Native.Some uu___5 -> - fail_duplicate setting1 - (print_codegen target))) settings - { - target_specific_settings = []; - default_settings = FStar_Pervasives_Native.None - } in - pes in - let empty_pes = - { - target_specific_settings = []; - default_settings = FStar_Pervasives_Native.None - } in - let pes = - FStar_Compiler_List.fold_right - (fun setting -> - fun pes1 -> - let uu___4 = parse_one_setting setting in - merge_parsed_extract_settings pes1 uu___4) - extract_settings1 empty_pes in - (FStar_Compiler_Effect.op_Colon_Equals memo - ((FStar_Pervasives_Native.Some pes), true); - FStar_Pervasives_Native.Some pes)) -let (should_extract : Prims.string -> codegen_t -> Prims.bool) = - fun m -> - fun tgt -> - let m1 = FStar_String.lowercase m in - let uu___ = extract_settings () in - match uu___ with - | FStar_Pervasives_Native.Some pes -> - ((let uu___2 = - let uu___3 = get_no_extract () in - let uu___4 = get_extract_namespace () in - let uu___5 = get_extract_module () in (uu___3, uu___4, uu___5) in - match uu___2 with - | ([], [], []) -> () - | uu___3 -> - failwith - "Incompatible options: --extract cannot be used with --no_extract, --extract_namespace or --extract_module"); - (let tsetting = - let uu___2 = - find_setting_for_target tgt pes.target_specific_settings in - match uu___2 with - | FStar_Pervasives_Native.Some s -> s - | FStar_Pervasives_Native.None -> - (match pes.default_settings with - | FStar_Pervasives_Native.Some s -> s - | FStar_Pervasives_Native.None -> "*") in - module_matches_namespace_filter m1 [tsetting])) - | FStar_Pervasives_Native.None -> - let should_extract_namespace m2 = - let uu___1 = get_extract_namespace () in - match uu___1 with - | [] -> false - | ns -> - FStar_Compiler_Effect.op_Bar_Greater ns - (FStar_Compiler_Util.for_some - (fun n -> - FStar_Compiler_Util.starts_with m2 - (FStar_String.lowercase n))) in - let should_extract_module m2 = - let uu___1 = get_extract_module () in - match uu___1 with - | [] -> false - | l -> - FStar_Compiler_Effect.op_Bar_Greater l - (FStar_Compiler_Util.for_some - (fun n -> (FStar_String.lowercase n) = m2)) in - (let uu___1 = no_extract m1 in Prims.op_Negation uu___1) && - (let uu___1 = - let uu___2 = get_extract_namespace () in - let uu___3 = get_extract_module () in (uu___2, uu___3) in - (match uu___1 with - | ([], []) -> true - | uu___2 -> - (should_extract_namespace m1) || (should_extract_module m1))) -let (should_be_already_cached : Prims.string -> Prims.bool) = - fun m -> - let uu___ = get_already_cached () in - match uu___ with - | FStar_Pervasives_Native.None -> false - | FStar_Pervasives_Native.Some already_cached_setting -> - module_matches_namespace_filter m already_cached_setting -let (profile_enabled : - Prims.string FStar_Pervasives_Native.option -> Prims.string -> Prims.bool) - = - fun modul_opt -> - fun phase -> - match modul_opt with - | FStar_Pervasives_Native.None -> - let uu___ = get_profile_component () in - matches_namespace_filter_opt phase uu___ - | FStar_Pervasives_Native.Some modul -> - ((let uu___ = get_profile () in - matches_namespace_filter_opt modul uu___) && - (let uu___ = get_profile_component () in - matches_namespace_filter_opt phase uu___)) - || - (((timing ()) && - (phase = "FStar.TypeChecker.Tc.process_one_decl")) - && (should_check modul)) -exception File_argument of Prims.string -let (uu___is_File_argument : Prims.exn -> Prims.bool) = - fun projectee -> - match projectee with | File_argument uu___ -> true | uu___ -> false -let (__proj__File_argument__item__uu___ : Prims.exn -> Prims.string) = - fun projectee -> match projectee with | File_argument uu___ -> uu___ -let (set_options : Prims.string -> FStar_Getopt.parse_cmdline_res) = - fun s -> - try - (fun uu___ -> - match () with - | () -> - if s = "" - then FStar_Getopt.Success - else - (let res = - FStar_Getopt.parse_string settable_specs - (fun s1 -> - FStar_Compiler_Effect.raise (File_argument s1); - FStar_Getopt.Error "set_options with file argument") s in - if res = FStar_Getopt.Success - then set_error_flags () - else res)) () - with - | File_argument s1 -> - let uu___1 = - FStar_Compiler_Util.format1 "File %s is not a valid option" s1 in - FStar_Getopt.Error uu___1 -let (get_vconfig : unit -> FStar_VConfig.vconfig) = - fun uu___ -> - let vcfg = - let uu___1 = get_initial_fuel () in - let uu___2 = get_max_fuel () in - let uu___3 = get_initial_ifuel () in - let uu___4 = get_max_ifuel () in - let uu___5 = get_detail_errors () in - let uu___6 = get_detail_hint_replay () in - let uu___7 = get_no_smt () in - let uu___8 = get_quake_lo () in - let uu___9 = get_quake_hi () in - let uu___10 = get_quake_keep () in - let uu___11 = get_retry () in - let uu___12 = get_smtencoding_elim_box () in - let uu___13 = get_smtencoding_nl_arith_repr () in - let uu___14 = get_smtencoding_l_arith_repr () in - let uu___15 = get_smtencoding_valid_intro () in - let uu___16 = get_smtencoding_valid_elim () in - let uu___17 = get_tcnorm () in - let uu___18 = get_no_plugins () in - let uu___19 = get_no_tactics () in - let uu___20 = get_z3cliopt () in - let uu___21 = get_z3smtopt () in - let uu___22 = get_z3refresh () in - let uu___23 = get_z3rlimit () in - let uu___24 = get_z3rlimit_factor () in - let uu___25 = get_z3seed () in - let uu___26 = get_trivial_pre_for_unannotated_effectful_fns () in - let uu___27 = get_reuse_hint_for () in - { - FStar_VConfig.initial_fuel = uu___1; - FStar_VConfig.max_fuel = uu___2; - FStar_VConfig.initial_ifuel = uu___3; - FStar_VConfig.max_ifuel = uu___4; - FStar_VConfig.detail_errors = uu___5; - FStar_VConfig.detail_hint_replay = uu___6; - FStar_VConfig.no_smt = uu___7; - FStar_VConfig.quake_lo = uu___8; - FStar_VConfig.quake_hi = uu___9; - FStar_VConfig.quake_keep = uu___10; - FStar_VConfig.retry = uu___11; - FStar_VConfig.smtencoding_elim_box = uu___12; - FStar_VConfig.smtencoding_nl_arith_repr = uu___13; - FStar_VConfig.smtencoding_l_arith_repr = uu___14; - FStar_VConfig.smtencoding_valid_intro = uu___15; - FStar_VConfig.smtencoding_valid_elim = uu___16; - FStar_VConfig.tcnorm = uu___17; - FStar_VConfig.no_plugins = uu___18; - FStar_VConfig.no_tactics = uu___19; - FStar_VConfig.z3cliopt = uu___20; - FStar_VConfig.z3smtopt = uu___21; - FStar_VConfig.z3refresh = uu___22; - FStar_VConfig.z3rlimit = uu___23; - FStar_VConfig.z3rlimit_factor = uu___24; - FStar_VConfig.z3seed = uu___25; - FStar_VConfig.trivial_pre_for_unannotated_effectful_fns = uu___26; - FStar_VConfig.reuse_hint_for = uu___27 - } in - vcfg -let (set_vconfig : FStar_VConfig.vconfig -> unit) = - fun vcfg -> - let option_as tag o = - match o with - | FStar_Pervasives_Native.None -> Unset - | FStar_Pervasives_Native.Some s -> tag s in - set_option "initial_fuel" (Int (vcfg.FStar_VConfig.initial_fuel)); - set_option "max_fuel" (Int (vcfg.FStar_VConfig.max_fuel)); - set_option "initial_ifuel" (Int (vcfg.FStar_VConfig.initial_ifuel)); - set_option "max_ifuel" (Int (vcfg.FStar_VConfig.max_ifuel)); - set_option "detail_errors" (Bool (vcfg.FStar_VConfig.detail_errors)); - set_option "detail_hint_replay" - (Bool (vcfg.FStar_VConfig.detail_hint_replay)); - set_option "no_smt" (Bool (vcfg.FStar_VConfig.no_smt)); - set_option "quake_lo" (Int (vcfg.FStar_VConfig.quake_lo)); - set_option "quake_hi" (Int (vcfg.FStar_VConfig.quake_hi)); - set_option "quake_keep" (Bool (vcfg.FStar_VConfig.quake_keep)); - set_option "retry" (Bool (vcfg.FStar_VConfig.retry)); - set_option "smtencoding.elim_box" - (Bool (vcfg.FStar_VConfig.smtencoding_elim_box)); - set_option "smtencoding.nl_arith_repr" - (String (vcfg.FStar_VConfig.smtencoding_nl_arith_repr)); - set_option "smtencoding.l_arith_repr" - (String (vcfg.FStar_VConfig.smtencoding_l_arith_repr)); - set_option "smtencoding.valid_intro" - (Bool (vcfg.FStar_VConfig.smtencoding_valid_intro)); - set_option "smtencoding.valid_elim" - (Bool (vcfg.FStar_VConfig.smtencoding_valid_elim)); - set_option "tcnorm" (Bool (vcfg.FStar_VConfig.tcnorm)); - set_option "no_plugins" (Bool (vcfg.FStar_VConfig.no_plugins)); - set_option "no_tactics" (Bool (vcfg.FStar_VConfig.no_tactics)); - (let uu___20 = - let uu___21 = - FStar_Compiler_List.map (fun uu___22 -> String uu___22) - vcfg.FStar_VConfig.z3cliopt in - List uu___21 in - set_option "z3cliopt" uu___20); - (let uu___21 = - let uu___22 = - FStar_Compiler_List.map (fun uu___23 -> String uu___23) - vcfg.FStar_VConfig.z3smtopt in - List uu___22 in - set_option "z3smtopt" uu___21); - set_option "z3refresh" (Bool (vcfg.FStar_VConfig.z3refresh)); - set_option "z3rlimit" (Int (vcfg.FStar_VConfig.z3rlimit)); - set_option "z3rlimit_factor" (Int (vcfg.FStar_VConfig.z3rlimit_factor)); - set_option "z3seed" (Int (vcfg.FStar_VConfig.z3seed)); - set_option "trivial_pre_for_unannotated_effectful_fns" - (Bool (vcfg.FStar_VConfig.trivial_pre_for_unannotated_effectful_fns)); - (let uu___27 = - option_as (fun uu___28 -> String uu___28) - vcfg.FStar_VConfig.reuse_hint_for in - set_option "reuse_hint_for" uu___27) \ No newline at end of file diff --git a/engine/backends/fstar/fstar-surface-ast/FStar_Parser_Const.ml b/engine/backends/fstar/fstar-surface-ast/FStar_Parser_Const.ml index e4fda7562..ccbbeae43 100644 --- a/engine/backends/fstar/fstar-surface-ast/FStar_Parser_Const.ml +++ b/engine/backends/fstar/fstar-surface-ast/FStar_Parser_Const.ml @@ -222,19 +222,19 @@ let (all_try_with_lid : FStar_Ident.lident) = p2l ["FStar"; "All"; "try_with"] let (effect_ALL_lid : unit -> FStar_Ident.lident) = fun uu___ -> - let uu___1 = FStar_Options.ml_ish () in + let uu___1 = false in if uu___1 then compiler_effect_ALL_lid else all_lid let (effect_ML_lid : unit -> FStar_Ident.lident) = fun uu___ -> - let uu___1 = FStar_Options.ml_ish () in + let uu___1 = false in if uu___1 then compiler_effect_ML_lid else all_ML_lid let (failwith_lid : unit -> FStar_Ident.lident) = fun uu___ -> - let uu___1 = FStar_Options.ml_ish () in + let uu___1 = false in if uu___1 then compiler_effect_failwith_lid else all_failwith_lid let (try_with_lid : unit -> FStar_Ident.lident) = fun uu___ -> - let uu___1 = FStar_Options.ml_ish () in + let uu___1 = false in if uu___1 then compiler_effect_try_with_lid else all_try_with_lid let (as_requires : FStar_Ident.lident) = pconst "as_requires" let (as_ensures : FStar_Ident.lident) = pconst "as_ensures" @@ -349,15 +349,10 @@ let (attr_substitute_lid : FStar_Ident.lident) = p2l ["FStar"; "Pervasives"; "Substitute"] let (well_founded_relation_lid : FStar_Ident.lident) = p2l ["FStar"; "WellFounded"; "well_founded_relation"] -let (gen_reset : ((unit -> Prims.int) * (unit -> unit))) = - let x = ref Prims.int_zero in - let gen uu___ = FStar_Compiler_Util.incr x; FStar_Compiler_Util.read x in - let reset uu___ = FStar_Compiler_Util.write x Prims.int_zero in - (gen, reset) -let (next_id : unit -> Prims.int) = FStar_Pervasives_Native.fst gen_reset + let (sli : FStar_Ident.lident -> Prims.string) = fun l -> - let uu___ = FStar_Options.print_real_names () in + let uu___ = false in if uu___ then FStar_Ident.string_of_lid l else @@ -504,6 +499,8 @@ let (mk_class_lid : FStar_Ident.lid) = fstar_tactics_lid' ["Typeclasses"; "mk_class"] let (tcresolve_lid : FStar_Ident.lid) = fstar_tactics_lid' ["Typeclasses"; "tcresolve"] +let (solve_lid : FStar_Ident.lid) = + fstar_tactics_lid' ["Typeclasses"; "solve"] let (tcclass_lid : FStar_Ident.lid) = fstar_tactics_lid' ["Typeclasses"; "tcclass"] let (tcinstance_lid : FStar_Ident.lid) = diff --git a/engine/backends/fstar/fstar-surface-ast/FStar_Parser_Parse.ml b/engine/backends/fstar/fstar-surface-ast/FStar_Parser_Parse.ml index 5f80cf775..62bd70c8a 100644 --- a/engine/backends/fstar/fstar-surface-ast/FStar_Parser_Parse.ml +++ b/engine/backends/fstar/fstar-surface-ast/FStar_Parser_Parse.ml @@ -3,7 +3,7 @@ open FStar_Errors open FStar_Compiler_List open FStar_Compiler_Util open FStar_Compiler_Range -open FStar_Options +(* open FStar_Options *) open FStar_Parser_Const open FStar_Parser_AST open FStar_Parser_Util @@ -196,7 +196,7 @@ open FStar_Errors open FStar_Compiler_List open FStar_Compiler_Util open FStar_Compiler_Range -open FStar_Options +(* open FStar_Options *) (* TODO : these files should be deprecated and removed *) (* open FStar_Syntax_Syntax *) open FStar_Parser_Const diff --git a/engine/backends/fstar/fstar-surface-ast/FStar_Parser_ParseIt.ml b/engine/backends/fstar/fstar-surface-ast/FStar_Parser_ParseIt.ml index d8e8ce58b..b6ba1bd8d 100644 --- a/engine/backends/fstar/fstar-surface-ast/FStar_Parser_ParseIt.ml +++ b/engine/backends/fstar/fstar-surface-ast/FStar_Parser_ParseIt.ml @@ -32,24 +32,20 @@ let setLexbufPos filename lexbuf line col = module Path = BatPathGen.OfString let find_file filename = - match FStar_Options.find_file filename with - | Some s -> - s - | None -> raise_err (Fatal_ModuleOrFileNotFound, U.format1 "Unable to find file: %s\n" filename) -let vfs_entries : (U.time * string) U.smap = U.smap_create (Z.of_int 1) +(* let vfs_entries : (U.time * string) U.smap = U.smap_create (Z.of_int 1) *) -let read_vfs_entry fname = - U.smap_try_find vfs_entries (U.normalize_file_path fname) +(* let read_vfs_entry fname = *) +(* U.smap_try_find vfs_entries (U.normalize_file_path fname) *) -let add_vfs_entry fname contents = - U.smap_add vfs_entries (U.normalize_file_path fname) (U.now (), contents) +(* let add_vfs_entry fname contents = *) +(* U.smap_add vfs_entries (U.normalize_file_path fname) (U.now (), contents) *) -let get_file_last_modification_time filename = - match read_vfs_entry filename with - | Some (mtime, _contents) -> mtime - | None -> U.get_file_last_modification_time filename +(* let get_file_last_modification_time filename = *) +(* match read_vfs_entry filename with *) +(* | Some (mtime, _contents) -> mtime *) +(* | None -> U.get_file_last_modification_time filename *) let read_physical_file (filename: string) = (* BatFile.with_file_in uses Unix.openfile (which isn't available in @@ -64,22 +60,17 @@ let read_physical_file (filename: string) = raise_err (Fatal_UnableToReadFile, U.format1 "Unable to read file %s\n" filename) let read_file (filename:string) = - let debug = FStar_Options.debug_any () in - match read_vfs_entry filename with - | Some (_mtime, contents) -> - if debug then U.print1 "Reading in-memory file %s\n" filename; - filename, contents - | None -> - let filename = find_file filename in - if debug then U.print1 "Opening file %s\n" filename; - filename, read_physical_file filename + let debug = false in + let filename = find_file filename in + if debug then U.print1 "Opening file %s\n" filename; + filename, read_physical_file filename let fs_extensions = [".fs"; ".fsi"] let fst_extensions = [".fst"; ".fsti"] let interface_extensions = [".fsti"; ".fsi"] let valid_extensions () = - fst_extensions @ if FStar_Options.ml_ish () then fs_extensions else [] + fst_extensions @ if false then fs_extensions else [] let has_extension file extensions = FStar_List.existsb (U.ends_with file) extensions diff --git a/engine/backends/fstar/fstar-surface-ast/FStar_Parser_ParseIt.mli b/engine/backends/fstar/fstar-surface-ast/FStar_Parser_ParseIt.mli deleted file mode 100755 index 86420e813..000000000 --- a/engine/backends/fstar/fstar-surface-ast/FStar_Parser_ParseIt.mli +++ /dev/null @@ -1,43 +0,0 @@ -module U = FStar_Compiler_Util -open FStar_Errors -open Lexing -open FStar_Sedlexing -module Codes = FStar_Errors_Codes - -type filename = string - -type input_frag = { - frag_fname:filename; - frag_text:string; - frag_line:Prims.int; - frag_col:Prims.int -} - -val read_vfs_entry : string -> (U.time * string) option -val add_vfs_entry: string -> string -> unit -val get_file_last_modification_time: string -> U.time - -type parse_frag = - | Filename of filename - | Toplevel of input_frag - | Incremental of input_frag - | Fragment of input_frag - -type parse_error = (Codes.raw_error * string * FStar_Compiler_Range.range) - -type code_fragment = { - range : FStar_Compiler_Range.range; - code: string; -} - -type parse_result = - | ASTFragment of (FStar_Parser_AST.inputFragment * (string * FStar_Compiler_Range.range) list) - | IncrementalFragment of ((FStar_Parser_AST.decl * code_fragment) list * (string * FStar_Compiler_Range.range) list * parse_error option) - | Term of FStar_Parser_AST.term - | ParseError of parse_error - -val parse: parse_frag -> parse_result - -val find_file: string -> string - -val parse_warn_error: string -> Codes.error_setting list diff --git a/engine/backends/fstar/fstar-surface-ast/FStar_Parser_ToDocument.ml b/engine/backends/fstar/fstar-surface-ast/FStar_Parser_ToDocument.ml index a05277458..23676511e 100644 --- a/engine/backends/fstar/fstar-surface-ast/FStar_Parser_ToDocument.ml +++ b/engine/backends/fstar/fstar-surface-ast/FStar_Parser_ToDocument.ml @@ -2261,7 +2261,7 @@ and (string_of_id_or_underscore : FStar_Ident.ident -> FStar_Pprint.document) let uu___ = (let uu___1 = FStar_Ident.string_of_id lid in FStar_Compiler_Util.starts_with uu___1 FStar_Ident.reserved_prefix) && - (let uu___1 = FStar_Options.print_real_names () in + (let uu___1 = false in Prims.op_Negation uu___1) in if uu___ then FStar_Pprint.underscore @@ -2274,7 +2274,7 @@ and (text_of_lid_or_underscore : FStar_Ident.lident -> FStar_Pprint.document) let uu___2 = FStar_Ident.ident_of_lid lid in FStar_Ident.string_of_id uu___2 in FStar_Compiler_Util.starts_with uu___1 FStar_Ident.reserved_prefix) && - (let uu___1 = FStar_Options.print_real_names () in + (let uu___1 = false in Prims.op_Negation uu___1) in if uu___ then FStar_Pprint.underscore diff --git a/engine/backends/fstar/fstar-surface-ast/FStar_Pervasives.ml b/engine/backends/fstar/fstar-surface-ast/FStar_Pervasives.ml index 3ef554ce2..d3a3ce23e 100644 --- a/engine/backends/fstar/fstar-surface-ast/FStar_Pervasives.ml +++ b/engine/backends/fstar/fstar-surface-ast/FStar_Pervasives.ml @@ -1,276 +1,4 @@ -open Prims -type pattern = unit - - -type eqtype_u = unit -type 'p spinoff = 'p let id : 'a . 'a -> 'a = fun x -> x -type ('a, 'uuuuu) trivial_pure_post = unit -type ('uuuuu, 'uuuuu1) ambient = unit -let normalize_term : 'uuuuu . 'uuuuu -> 'uuuuu = fun x -> x -type 'a normalize = 'a -type norm_step = - | Simpl - | Weak - | HNF - | Primops - | Delta - | Zeta - | ZetaFull - | Iota - | NBE - | Reify - | UnfoldOnly of Prims.string Prims.list - | UnfoldFully of Prims.string Prims.list - | UnfoldAttr of Prims.string Prims.list - | UnfoldQual of Prims.string Prims.list - | UnfoldNamespace of Prims.string Prims.list - | Unmeta - | Unascribe -let (uu___is_Simpl : norm_step -> Prims.bool) = - fun projectee -> match projectee with | Simpl -> true | uu___ -> false -let (uu___is_Weak : norm_step -> Prims.bool) = - fun projectee -> match projectee with | Weak -> true | uu___ -> false -let (uu___is_HNF : norm_step -> Prims.bool) = - fun projectee -> match projectee with | HNF -> true | uu___ -> false -let (uu___is_Primops : norm_step -> Prims.bool) = - fun projectee -> match projectee with | Primops -> true | uu___ -> false -let (uu___is_Delta : norm_step -> Prims.bool) = - fun projectee -> match projectee with | Delta -> true | uu___ -> false -let (uu___is_Zeta : norm_step -> Prims.bool) = - fun projectee -> match projectee with | Zeta -> true | uu___ -> false -let (uu___is_ZetaFull : norm_step -> Prims.bool) = - fun projectee -> match projectee with | ZetaFull -> true | uu___ -> false -let (uu___is_Iota : norm_step -> Prims.bool) = - fun projectee -> match projectee with | Iota -> true | uu___ -> false -let (uu___is_NBE : norm_step -> Prims.bool) = - fun projectee -> match projectee with | NBE -> true | uu___ -> false -let (uu___is_Reify : norm_step -> Prims.bool) = - fun projectee -> match projectee with | Reify -> true | uu___ -> false -let (uu___is_UnfoldOnly : norm_step -> Prims.bool) = - fun projectee -> - match projectee with | UnfoldOnly _0 -> true | uu___ -> false -let (__proj__UnfoldOnly__item___0 : norm_step -> Prims.string Prims.list) = - fun projectee -> match projectee with | UnfoldOnly _0 -> _0 -let (uu___is_UnfoldFully : norm_step -> Prims.bool) = - fun projectee -> - match projectee with | UnfoldFully _0 -> true | uu___ -> false -let (__proj__UnfoldFully__item___0 : norm_step -> Prims.string Prims.list) = - fun projectee -> match projectee with | UnfoldFully _0 -> _0 -let (uu___is_UnfoldAttr : norm_step -> Prims.bool) = - fun projectee -> - match projectee with | UnfoldAttr _0 -> true | uu___ -> false -let (__proj__UnfoldAttr__item___0 : norm_step -> Prims.string Prims.list) = - fun projectee -> match projectee with | UnfoldAttr _0 -> _0 -let (uu___is_UnfoldQual : norm_step -> Prims.bool) = - fun projectee -> - match projectee with | UnfoldQual _0 -> true | uu___ -> false -let (__proj__UnfoldQual__item___0 : norm_step -> Prims.string Prims.list) = - fun projectee -> match projectee with | UnfoldQual _0 -> _0 -let (uu___is_UnfoldNamespace : norm_step -> Prims.bool) = - fun projectee -> - match projectee with | UnfoldNamespace _0 -> true | uu___ -> false -let (__proj__UnfoldNamespace__item___0 : - norm_step -> Prims.string Prims.list) = - fun projectee -> match projectee with | UnfoldNamespace _0 -> _0 -let (uu___is_Unmeta : norm_step -> Prims.bool) = - fun projectee -> match projectee with | Unmeta -> true | uu___ -> false -let (uu___is_Unascribe : norm_step -> Prims.bool) = - fun projectee -> match projectee with | Unascribe -> true | uu___ -> false -let (simplify : norm_step) = Simpl -let (weak : norm_step) = Weak -let (hnf : norm_step) = HNF -let (primops : norm_step) = Primops -let (delta : norm_step) = Delta -let (zeta : norm_step) = Zeta -let (zeta_full : norm_step) = ZetaFull -let (iota : norm_step) = Iota -let (nbe : norm_step) = NBE -let (reify_ : norm_step) = Reify -let (delta_only : Prims.string Prims.list -> norm_step) = - fun s -> UnfoldOnly s -let (delta_fully : Prims.string Prims.list -> norm_step) = - fun s -> UnfoldFully s -let (delta_attr : Prims.string Prims.list -> norm_step) = - fun s -> UnfoldAttr s -let (delta_qualifier : Prims.string Prims.list -> norm_step) = - fun s -> UnfoldAttr s -let (delta_namespace : Prims.string Prims.list -> norm_step) = - fun s -> UnfoldNamespace s -let (unmeta : norm_step) = Unmeta -let (unascribe : norm_step) = Unascribe -let (norm : norm_step Prims.list -> unit -> Obj.t -> Obj.t) = - fun uu___ -> fun uu___1 -> fun x -> x -type ('a, 'x, 'uuuuu) pure_return = unit -type ('a, 'b, 'wp1, 'wp2, 'uuuuu) pure_bind_wp = 'wp1 -type ('a, 'p, 'wputhen, 'wpuelse, 'uuuuu) pure_if_then_else = unit -type ('a, 'wp, 'uuuuu) pure_ite_wp = unit -type ('a, 'b, 'wp, 'uuuuu) pure_close_wp = unit -type ('a, 'uuuuu) pure_null_wp = unit -type ('p, 'uuuuu) pure_assert_wp = unit -type ('p, 'uuuuu) pure_assume_wp = unit -type ('a, 'pre, 'post, 'uuuuu) div_hoare_to_wp = unit -type 'heap st_pre_h = unit -type ('heap, 'a, 'pre) st_post_h' = unit -type ('heap, 'a) st_post_h = unit -type ('heap, 'a) st_wp_h = unit -type ('heap, 'a, 'x, 'p, 'uuuuu) st_return = 'p -type ('heap, 'a, 'b, 'wp1, 'wp2, 'p, 'h0) st_bind_wp = 'wp1 -type ('heap, 'a, 'p, 'wputhen, 'wpuelse, 'post, 'h0) st_if_then_else = unit -type ('heap, 'a, 'wp, 'post, 'h0) st_ite_wp = unit -type ('heap, 'a, 'wp1, 'wp2) st_stronger = unit -type ('heap, 'a, 'b, 'wp, 'p, 'h) st_close_wp = unit -type ('heap, 'a, 'wp) st_trivial = unit -type 'a result = - | V of 'a - | E of Prims.exn - | Err of Prims.string -let uu___is_V : 'a . 'a result -> Prims.bool = - fun projectee -> match projectee with | V v -> true | uu___ -> false -let __proj__V__item__v : 'a . 'a result -> 'a = - fun projectee -> match projectee with | V v -> v -let uu___is_E : 'a . 'a result -> Prims.bool = - fun projectee -> match projectee with | E e -> true | uu___ -> false -let __proj__E__item__e : 'a . 'a result -> Prims.exn = - fun projectee -> match projectee with | E e -> e -let uu___is_Err : 'a . 'a result -> Prims.bool = - fun projectee -> match projectee with | Err msg -> true | uu___ -> false -let __proj__Err__item__msg : 'a . 'a result -> Prims.string = - fun projectee -> match projectee with | Err msg -> msg -type ex_pre = unit -type ('a, 'pre) ex_post' = unit -type 'a ex_post = unit -type 'a ex_wp = unit -type ('a, 'x, 'p) ex_return = 'p -type ('a, 'b, 'wp1, 'wp2, 'p) ex_bind_wp = unit -type ('a, 'p, 'wputhen, 'wpuelse, 'post) ex_if_then_else = unit -type ('a, 'wp, 'post) ex_ite_wp = unit -type ('a, 'wp1, 'wp2) ex_stronger = unit -type ('a, 'b, 'wp, 'p) ex_close_wp = unit -type ('a, 'wp) ex_trivial = 'wp -type ('a, 'wp, 'p) lift_div_exn = 'wp -type 'h all_pre_h = unit -type ('h, 'a, 'pre) all_post_h' = unit -type ('h, 'a) all_post_h = unit -type ('h, 'a) all_wp_h = unit -type ('heap, 'a, 'x, 'p, 'uuuuu) all_return = 'p -type ('heap, 'a, 'b, 'wp1, 'wp2, 'p, 'h0) all_bind_wp = 'wp1 -type ('heap, 'a, 'p, 'wputhen, 'wpuelse, 'post, 'h0) all_if_then_else = unit -type ('heap, 'a, 'wp, 'post, 'h0) all_ite_wp = unit -type ('heap, 'a, 'wp1, 'wp2) all_stronger = unit -type ('heap, 'a, 'b, 'wp, 'p, 'h) all_close_wp = unit -type ('heap, 'a, 'wp) all_trivial = unit -type 'uuuuu inversion = unit type ('a, 'b) either = - | Inl of 'a - | Inr of 'b -let uu___is_Inl : 'a 'b . ('a, 'b) either -> Prims.bool = - fun projectee -> match projectee with | Inl v -> true | uu___ -> false -let __proj__Inl__item__v : 'a 'b . ('a, 'b) either -> 'a = - fun projectee -> match projectee with | Inl v -> v -let uu___is_Inr : 'a 'b . ('a, 'b) either -> Prims.bool = - fun projectee -> match projectee with | Inr v -> true | uu___ -> false -let __proj__Inr__item__v : 'a 'b . ('a, 'b) either -> 'b = - fun projectee -> match projectee with | Inr v -> v -let dfst : 'a 'b . ('a, 'b) Prims.dtuple2 -> 'a = - fun t -> Prims.__proj__Mkdtuple2__item___1 t -let dsnd : 'a 'b . ('a, 'b) Prims.dtuple2 -> 'b = - fun t -> Prims.__proj__Mkdtuple2__item___2 t -type ('a, 'b, 'c) dtuple3 = - | Mkdtuple3 of 'a * 'b * 'c -let uu___is_Mkdtuple3 : 'a 'b 'c . ('a, 'b, 'c) dtuple3 -> Prims.bool = - fun projectee -> true -let __proj__Mkdtuple3__item___1 : 'a 'b 'c . ('a, 'b, 'c) dtuple3 -> 'a = - fun projectee -> match projectee with | Mkdtuple3 (_1, _2, _3) -> _1 -let __proj__Mkdtuple3__item___2 : 'a 'b 'c . ('a, 'b, 'c) dtuple3 -> 'b = - fun projectee -> match projectee with | Mkdtuple3 (_1, _2, _3) -> _2 -let __proj__Mkdtuple3__item___3 : 'a 'b 'c . ('a, 'b, 'c) dtuple3 -> 'c = - fun projectee -> match projectee with | Mkdtuple3 (_1, _2, _3) -> _3 -type ('a, 'b, 'c, 'd) dtuple4 = - | Mkdtuple4 of 'a * 'b * 'c * 'd -let uu___is_Mkdtuple4 : 'a 'b 'c 'd . ('a, 'b, 'c, 'd) dtuple4 -> Prims.bool - = fun projectee -> true -let __proj__Mkdtuple4__item___1 : - 'a 'b 'c 'd . ('a, 'b, 'c, 'd) dtuple4 -> 'a = - fun projectee -> match projectee with | Mkdtuple4 (_1, _2, _3, _4) -> _1 -let __proj__Mkdtuple4__item___2 : - 'a 'b 'c 'd . ('a, 'b, 'c, 'd) dtuple4 -> 'b = - fun projectee -> match projectee with | Mkdtuple4 (_1, _2, _3, _4) -> _2 -let __proj__Mkdtuple4__item___3 : - 'a 'b 'c 'd . ('a, 'b, 'c, 'd) dtuple4 -> 'c = - fun projectee -> match projectee with | Mkdtuple4 (_1, _2, _3, _4) -> _3 -let __proj__Mkdtuple4__item___4 : - 'a 'b 'c 'd . ('a, 'b, 'c, 'd) dtuple4 -> 'd = - fun projectee -> match projectee with | Mkdtuple4 (_1, _2, _3, _4) -> _4 -let rec false_elim : 'uuuuu . unit -> 'uuuuu = fun uu___ -> false_elim () -type __internal_ocaml_attributes = - | PpxDerivingShow - | PpxDerivingShowConstant of Prims.string - | PpxDerivingYoJson - | CInline - | Substitute - | Gc - | Comment of Prims.string - | CPrologue of Prims.string - | CEpilogue of Prims.string - | CConst of Prims.string - | CCConv of Prims.string - | CAbstractStruct - | CIfDef - | CMacro -let (uu___is_PpxDerivingShow : __internal_ocaml_attributes -> Prims.bool) = - fun projectee -> - match projectee with | PpxDerivingShow -> true | uu___ -> false -let (uu___is_PpxDerivingShowConstant : - __internal_ocaml_attributes -> Prims.bool) = - fun projectee -> - match projectee with - | PpxDerivingShowConstant _0 -> true - | uu___ -> false -let (__proj__PpxDerivingShowConstant__item___0 : - __internal_ocaml_attributes -> Prims.string) = - fun projectee -> match projectee with | PpxDerivingShowConstant _0 -> _0 -let (uu___is_PpxDerivingYoJson : __internal_ocaml_attributes -> Prims.bool) = - fun projectee -> - match projectee with | PpxDerivingYoJson -> true | uu___ -> false -let (uu___is_CInline : __internal_ocaml_attributes -> Prims.bool) = - fun projectee -> match projectee with | CInline -> true | uu___ -> false -let (uu___is_Substitute : __internal_ocaml_attributes -> Prims.bool) = - fun projectee -> match projectee with | Substitute -> true | uu___ -> false -let (uu___is_Gc : __internal_ocaml_attributes -> Prims.bool) = - fun projectee -> match projectee with | Gc -> true | uu___ -> false -let (uu___is_Comment : __internal_ocaml_attributes -> Prims.bool) = - fun projectee -> match projectee with | Comment _0 -> true | uu___ -> false -let (__proj__Comment__item___0 : __internal_ocaml_attributes -> Prims.string) - = fun projectee -> match projectee with | Comment _0 -> _0 -let (uu___is_CPrologue : __internal_ocaml_attributes -> Prims.bool) = - fun projectee -> - match projectee with | CPrologue _0 -> true | uu___ -> false -let (__proj__CPrologue__item___0 : - __internal_ocaml_attributes -> Prims.string) = - fun projectee -> match projectee with | CPrologue _0 -> _0 -let (uu___is_CEpilogue : __internal_ocaml_attributes -> Prims.bool) = - fun projectee -> - match projectee with | CEpilogue _0 -> true | uu___ -> false -let (__proj__CEpilogue__item___0 : - __internal_ocaml_attributes -> Prims.string) = - fun projectee -> match projectee with | CEpilogue _0 -> _0 -let (uu___is_CConst : __internal_ocaml_attributes -> Prims.bool) = - fun projectee -> match projectee with | CConst _0 -> true | uu___ -> false -let (__proj__CConst__item___0 : __internal_ocaml_attributes -> Prims.string) - = fun projectee -> match projectee with | CConst _0 -> _0 -let (uu___is_CCConv : __internal_ocaml_attributes -> Prims.bool) = - fun projectee -> match projectee with | CCConv _0 -> true | uu___ -> false -let (__proj__CCConv__item___0 : __internal_ocaml_attributes -> Prims.string) - = fun projectee -> match projectee with | CCConv _0 -> _0 -let (uu___is_CAbstractStruct : __internal_ocaml_attributes -> Prims.bool) = - fun projectee -> - match projectee with | CAbstractStruct -> true | uu___ -> false -let (uu___is_CIfDef : __internal_ocaml_attributes -> Prims.bool) = - fun projectee -> match projectee with | CIfDef -> true | uu___ -> false -let (uu___is_CMacro : __internal_ocaml_attributes -> Prims.bool) = - fun projectee -> match projectee with | CMacro -> true | uu___ -> false -let singleton : 'uuuuu . 'uuuuu -> 'uuuuu = fun x -> x -type 'a eqtype_as_type = 'a -let coerce_eq : 'a 'b . unit -> 'a -> 'b = - fun uu___1 -> fun uu___ -> (fun uu___ -> fun x -> Obj.magic x) uu___1 uu___ \ No newline at end of file + | Inl of 'a + | Inr of 'b diff --git a/engine/backends/fstar/fstar-surface-ast/FStar_Pervasives_Native.ml b/engine/backends/fstar/fstar-surface-ast/FStar_Pervasives_Native.ml index f32c26377..72406f94f 100644 --- a/engine/backends/fstar/fstar-surface-ast/FStar_Pervasives_Native.ml +++ b/engine/backends/fstar/fstar-surface-ast/FStar_Pervasives_Native.ml @@ -1,4 +1,3 @@ - type 'a option' = 'a option = | None | Some of 'a[@@deriving yojson,show] @@ -7,279 +6,5 @@ type 'a option = 'a option' = | None | Some of 'a[@@deriving yojson,show] -let uu___is_None = function None -> true | _ -> false -let uu___is_Some = function Some _ -> true | _ -> false -let __proj__Some__item__v = function Some x -> x | _ -> assert false - -(* 'a * 'b *) -type ('a,'b) tuple2 = 'a * 'b[@@deriving yojson,show] - let fst = Stdlib.fst let snd = Stdlib.snd - -let __proj__Mktuple2__1 = fst -let __proj__Mktuple2__2 = snd - -type ('a,'b,'c) tuple3 = - 'a* 'b* 'c -[@@deriving yojson,show] -let uu___is_Mktuple3 projectee = true -let __proj__Mktuple3__item___1 projectee = - match projectee with | (_1,_2,_3) -> _1 -let __proj__Mktuple3__item___2 projectee = - match projectee with | (_1,_2,_3) -> _2 -let __proj__Mktuple3__item___3 projectee = - match projectee with | (_1,_2,_3) -> _3 - -type ('a,'b,'c,'d) tuple4 = - 'a* 'b* 'c* 'd -[@@deriving yojson,show] -let uu___is_Mktuple4 projectee = true -let __proj__Mktuple4__item___1 projectee = - match projectee with | (_1,_2,_3,_4) -> _1 -let __proj__Mktuple4__item___2 projectee = - match projectee with | (_1,_2,_3,_4) -> _2 -let __proj__Mktuple4__item___3 projectee = - match projectee with | (_1,_2,_3,_4) -> _3 -let __proj__Mktuple4__item___4 projectee = - match projectee with | (_1,_2,_3,_4) -> _4 - -type ('a,'b,'c,'d,'e) tuple5 = - 'a* 'b* 'c* 'd* 'e -[@@deriving yojson,show] -let uu___is_Mktuple5 projectee = true -let __proj__Mktuple5__item___1 projectee = - match projectee with | (_1,_2,_3,_4,_5) -> _1 -let __proj__Mktuple5__item___2 projectee = - match projectee with | (_1,_2,_3,_4,_5) -> _2 -let __proj__Mktuple5__item___3 projectee = - match projectee with | (_1,_2,_3,_4,_5) -> _3 -let __proj__Mktuple5__item___4 projectee = - match projectee with | (_1,_2,_3,_4,_5) -> _4 -let __proj__Mktuple5__item___5 projectee = - match projectee with | (_1,_2,_3,_4,_5) -> _5 - -type ('a,'b,'c,'d,'e,'f) tuple6 = - 'a* 'b* 'c* 'd* 'e* 'f -[@@deriving yojson,show] -let uu___is_Mktuple6 projectee = true -let __proj__Mktuple6__item___1 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6) -> _1 -let __proj__Mktuple6__item___2 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6) -> _2 -let __proj__Mktuple6__item___3 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6) -> _3 -let __proj__Mktuple6__item___4 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6) -> _4 -let __proj__Mktuple6__item___5 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6) -> _5 -let __proj__Mktuple6__item___6 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6) -> _6 - -type ('a,'b,'c,'d,'e,'f,'g) tuple7 = - 'a* 'b* 'c* 'd* 'e* 'f* 'g -[@@deriving yojson,show] -let uu___is_Mktuple7 projectee = true -let __proj__Mktuple7__item___1 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7) -> _1 -let __proj__Mktuple7__item___2 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7) -> _2 -let __proj__Mktuple7__item___3 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7) -> _3 -let __proj__Mktuple7__item___4 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7) -> _4 -let __proj__Mktuple7__item___5 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7) -> _5 -let __proj__Mktuple7__item___6 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7) -> _6 -let __proj__Mktuple7__item___7 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7) -> _7 - -type ('a,'b,'c,'d,'e,'f,'g,'h) tuple8 = - 'a* 'b* 'c* 'd* 'e* 'f* 'g* 'h -[@@deriving yojson,show] -let uu___is_Mktuple8 projectee = true -let __proj__Mktuple8__item___1 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8) -> _1 -let __proj__Mktuple8__item___2 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8) -> _2 -let __proj__Mktuple8__item___3 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8) -> _3 -let __proj__Mktuple8__item___4 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8) -> _4 -let __proj__Mktuple8__item___5 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8) -> _5 -let __proj__Mktuple8__item___6 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8) -> _6 -let __proj__Mktuple8__item___7 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8) -> _7 -let __proj__Mktuple8__item___8 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8) -> _8 - -type ('a,'b,'c,'d,'e,'f,'g,'h,'i) tuple9 = - 'a *'b *'c *'d *'e *'f *'g *'h *'i -[@@deriving yojson,show] -let uu___is_Mktuple9 projectee = true -let __proj__Mktuple9__item___1 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9) -> _1 -let __proj__Mktuple9__item___2 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9) -> _2 -let __proj__Mktuple9__item___3 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9) -> _3 -let __proj__Mktuple9__item___4 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9) -> _4 -let __proj__Mktuple9__item___5 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9) -> _5 -let __proj__Mktuple9__item___6 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9) -> _6 -let __proj__Mktuple9__item___7 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9) -> _7 -let __proj__Mktuple9__item___8 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9) -> _8 -let __proj__Mktuple9__item___9 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9) -> _9 - -type ('a,'b,'c,'d,'e,'f,'g,'h,'i,'j) tuple10 = - 'a *'b *'c *'d *'e *'f *'g *'h *'i *'j -[@@deriving yojson,show] -let uu___is_Mktuple10 projectee = true -let __proj__Mktuple10__item___1 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10) -> _1 -let __proj__Mktuple10__item___2 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10) -> _2 -let __proj__Mktuple10__item___3 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10) -> _3 -let __proj__Mktuple10__item___4 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10) -> _4 -let __proj__Mktuple10__item___5 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10) -> _5 -let __proj__Mktuple10__item___6 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10) -> _6 -let __proj__Mktuple10__item___7 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10) -> _7 -let __proj__Mktuple10__item___8 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10) -> _8 -let __proj__Mktuple10__item___9 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10) -> _9 -let __proj__Mktuple10__item___10 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10) -> _10 - -type ('a,'b,'c,'d,'e,'f,'g,'h,'i,'j,'k) tuple11 = - 'a *'b *'c *'d *'e *'f *'g *'h *'i *'j *'k -[@@deriving yojson,show] -let uu___is_Mktuple11 projectee = true -let __proj__Mktuple11__item___1 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11) -> _1 -let __proj__Mktuple11__item___2 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11) -> _2 -let __proj__Mktuple11__item___3 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11) -> _3 -let __proj__Mktuple11__item___4 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11) -> _4 -let __proj__Mktuple11__item___5 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11) -> _5 -let __proj__Mktuple11__item___6 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11) -> _6 -let __proj__Mktuple11__item___7 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11) -> _7 -let __proj__Mktuple11__item___8 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11) -> _8 -let __proj__Mktuple11__item___9 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11) -> _9 -let __proj__Mktuple11__item___10 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11) -> _10 -let __proj__Mktuple11__item___11 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11) -> _11 - -type ('a,'b,'c,'d,'e,'f,'g,'h,'i,'j,'k,'l) tuple12 = - 'a *'b *'c *'d *'e *'f *'g *'h *'i *'j *'k *'l -[@@deriving yojson,show] -let uu___is_Mktuple12 projectee = true -let __proj__Mktuple12__item___1 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12) -> _1 -let __proj__Mktuple12__item___2 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12) -> _2 -let __proj__Mktuple12__item___3 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12) -> _3 -let __proj__Mktuple12__item___4 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12) -> _4 -let __proj__Mktuple12__item___5 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12) -> _5 -let __proj__Mktuple12__item___6 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12) -> _6 -let __proj__Mktuple12__item___7 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12) -> _7 -let __proj__Mktuple12__item___8 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12) -> _8 -let __proj__Mktuple12__item___9 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12) -> _9 -let __proj__Mktuple12__item___10 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12) -> _10 -let __proj__Mktuple12__item___11 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12) -> _11 -let __proj__Mktuple12__item___12 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12) -> _12 - -type ('a,'b,'c,'d,'e,'f,'g,'h,'i,'j,'k,'l,'m) tuple13 = - 'a *'b *'c *'d *'e *'f *'g *'h *'i *'j *'k *'l *'m -[@@deriving yojson,show] -let uu___is_Mktuple13 projectee = true -let __proj__Mktuple13__item___1 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13) -> _1 -let __proj__Mktuple13__item___2 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13) -> _2 -let __proj__Mktuple13__item___3 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13) -> _3 -let __proj__Mktuple13__item___4 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13) -> _4 -let __proj__Mktuple13__item___5 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13) -> _5 -let __proj__Mktuple13__item___6 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13) -> _6 -let __proj__Mktuple13__item___7 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13) -> _7 -let __proj__Mktuple13__item___8 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13) -> _8 -let __proj__Mktuple13__item___9 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13) -> _9 -let __proj__Mktuple13__item___10 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13) -> _10 -let __proj__Mktuple13__item___11 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13) -> _11 -let __proj__Mktuple13__item___12 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13) -> _12 -let __proj__Mktuple13__item___13 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13) -> _13 - -type ('a,'b,'c,'d,'e,'f,'g,'h,'i,'j,'k,'l,'m,'n) tuple14 = - 'a *'b *'c *'d *'e *'f *'g *'h *'i *'j *'k *'l *'m *'n -[@@deriving yojson,show] -let uu___is_Mktuple14 projectee = true -let __proj__Mktuple14__item___1 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14) -> _1 -let __proj__Mktuple14__item___2 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14) -> _2 -let __proj__Mktuple14__item___3 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14) -> _3 -let __proj__Mktuple14__item___4 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14) -> _4 -let __proj__Mktuple14__item___5 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14) -> _5 -let __proj__Mktuple14__item___6 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14) -> _6 -let __proj__Mktuple14__item___7 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14) -> _7 -let __proj__Mktuple14__item___8 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14) -> _8 -let __proj__Mktuple14__item___9 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14) -> _9 -let __proj__Mktuple14__item___10 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14) -> _10 -let __proj__Mktuple14__item___11 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14) -> _11 -let __proj__Mktuple14__item___12 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14) -> _12 -let __proj__Mktuple14__item___13 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14) -> _13 -let __proj__Mktuple14__item___14 projectee = - match projectee with | (_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14) -> _14 diff --git a/engine/backends/fstar/fstar-surface-ast/FStar_Platform.ml b/engine/backends/fstar/fstar-surface-ast/FStar_Platform.ml deleted file mode 100644 index 038ed9060..000000000 --- a/engine/backends/fstar/fstar-surface-ast/FStar_Platform.ml +++ /dev/null @@ -1,17 +0,0 @@ -type sys = -| Windows -| Posix - -let system = - if Sys.win32 || Sys.cygwin then - Windows - else - Posix - -let exe name = - if Sys.unix then - name - else - name^".exe" - -let is_fstar_compiler_using_ocaml = true diff --git a/engine/backends/fstar/fstar-surface-ast/FStar_ST.ml b/engine/backends/fstar/fstar-surface-ast/FStar_ST.ml deleted file mode 100644 index a27ecf12b..000000000 --- a/engine/backends/fstar/fstar-surface-ast/FStar_ST.ml +++ /dev/null @@ -1,28 +0,0 @@ -(* https://www.lexifi.com/blog/references-physical-equality *) - -open FStar_CommonST - -type ('a, 'b) mref = ('a, 'b) FStar_Monotonic_Heap.mref - -type 'a ref = 'a FStar_Monotonic_Heap.ref - -let ref_to_yojson _ _ = `Null -let ref_of_yojson _ _ = failwith "cannot readback" - -let read = read - -let op_Bang = op_Bang - -let write = write - -let op_Colon_Equals = op_Colon_Equals - -let alloc = alloc - -let recall = recall -let get = get - -type 'a witnessed = 'a FStar_CommonST.witnessed - -let gst_witness = gst_witness -let gst_recall = gst_recall diff --git a/engine/backends/fstar/fstar-surface-ast/FStar_String.ml b/engine/backends/fstar/fstar-surface-ast/FStar_String.ml index 9dcff4a94..1cfe3f803 100644 --- a/engine/backends/fstar/fstar-surface-ast/FStar_String.ml +++ b/engine/backends/fstar/fstar-surface-ast/FStar_String.ml @@ -16,28 +16,15 @@ let split seps s = repeat_split l seps in repeat_split [s] seps let compare x y = Z.of_int (BatString.compare x y) -type char = FStar_Char.char let concat = BatString.concat let length s = Z.of_int (BatUTF8.length s) -let strlen s = length s let substring s i j = BatUTF8.init (Z.to_int j) (fun k -> BatUTF8.get s (k + Z.to_int i)) -let sub = substring let get s i = BatUChar.code (BatUTF8.get s (Z.to_int i)) -let collect f s = - let r = ref "" in - BatUTF8.iter (fun c -> r := !r ^ f (BatUChar.code c)) s; !r let lowercase = BatString.lowercase_ascii let uppercase = BatString.uppercase_ascii let escaped = BatString.escaped -let index = get -exception Found of int -let index_of s c = - let c = BatUChar.chr c in - try let _ = BatUTF8.iteri (fun c' i -> if c = c' then raise (Found i) else ()) s in Z.of_int (-1) - with Found i -> Z.of_int i let list_of_string s = BatList.init (BatUTF8.length s) (fun i -> BatUChar.code (BatUTF8.get s i)) let string_of_list l = BatUTF8.init (BatList.length l) (fun i -> BatUChar.chr (BatList.at l i)) -let string_of_char (c:char) = BatString.of_char (Char.chr c) diff --git a/engine/backends/fstar/fstar-surface-ast/FStar_UInt16.ml b/engine/backends/fstar/fstar-surface-ast/FStar_UInt16.ml deleted file mode 100644 index 69409412a..000000000 --- a/engine/backends/fstar/fstar-surface-ast/FStar_UInt16.ml +++ /dev/null @@ -1,105 +0,0 @@ -(* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! *) -(* THIS IS AN AUTOGENERATED FILE! See ulib/ml/Makefile *) -(* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! *) - -(* This file is meant to be concatenated to FStar_Ints.ml.body *) -module M = Stdint.Uint16 -type uint16 = M.t -type t = M.t -let n = Prims.of_int 16 - -let uint_to_t x = M.of_string (Z.to_string x) -let __uint_to_t = uint_to_t -(* This .ml.body file is concatenated to every .ml.prefix file in this - * directory (ulib/ml/) to generate the OCaml realizations for machine - * integers, as they all pretty much share their definitions and are - * based on Stdint. *) - -let v (x:t) : Prims.int = Prims.parse_int (M.to_string x) - -let zero = M.zero -let one = M.one -let ones = M.pred M.zero - -(* Reexport add, plus aliases *) -let add = M.add -let add_underspec = M.add -let add_mod = M.add - -(* Reexport sub, plus aliases *) -let sub = M.sub -let sub_underspec = M.sub -let sub_mod = M.sub - -(* Reexport mul, plus aliases *) -let mul = M.mul -let mul_underspec = M.mul -let mul_mod = M.mul - -(* Conversions to Zarith's int *) -let to_int (x:t) : Z.t = Z.of_string (M.to_string x) -let of_int (x:Z.t) : t = M.of_string (Z.to_string x) - -(* Conversion to native ints; these are potentially unsafe and not part - * of the interface: they are meant to be called only from OCaml code - * that is doing the right thing *) -let of_native_int (x:int) : t = M.of_int x -let to_native_int (x:t) : int = M.to_int x - -(* Just reexport these *) -let div = M.div -let rem = M.rem -let logand = M.logand -let logxor = M.logxor -let logor = M.logor -let lognot = M.lognot -let to_string = M.to_string -let of_string = M.of_string - -let to_string_hex = M.to_string_hex - -let to_string_hex_pad i = - let s0 = M.to_string_hex i in - let len = (String.length s0 - 2) in - let s1 = String.sub s0 2 len in (* Remove leading "0x" *) - let zeroes = String.make ((Z.to_int n / 4) - len) '0' in - zeroes ^ s1 - -(* The shifts take a uint32 argument, so we need to convert *) -let shift_right n i = M.shift_right n (Stdint.Uint32.to_int i) -let shift_left n i = M.shift_left n (Stdint.Uint32.to_int i) -let shift_arithmetic_right = shift_right - -(* Comparison operators *) -let eq (a:t) (b:t) : bool = a = b -let gt (a:t) (b:t) : bool = a > b -let gte (a:t) (b:t) : bool = a >= b -let lt (a:t) (b:t) : bool = a < b -let lte (a:t) (b:t) : bool = a <= b - -(* NOT Constant time operators *) -let eq_mask (a:t) (b:t) : t = if a = b then ones else zero -let gte_mask (a:t) (b:t) : t = if a >= b then ones else zero - -(* Infix notations *) -let op_Plus_Hat = add -let op_Plus_Question_Hat = add_underspec -let op_Plus_Percent_Hat = add_mod -let op_Subtraction_Hat = sub -let op_Subtraction_Question_Hat = sub_underspec -let op_Subtraction_Percent_Hat = sub_mod -let op_Star_Hat = mul -let op_Star_Question_Hat = mul_underspec -let op_Star_Percent_Hat = mul_mod -let op_Slash_Hat = div -let op_Percent_Hat = rem -let op_Hat_Hat = logxor -let op_Amp_Hat = logand -let op_Bar_Hat = logor -let op_Less_Less_Hat = shift_left -let op_Greater_Greater_Hat = shift_right -let op_Equals_Hat = eq -let op_Greater_Hat = gt -let op_Greater_Equals_Hat = gte -let op_Less_Hat = lt -let op_Less_Equals_Hat = lte diff --git a/engine/backends/fstar/fstar-surface-ast/FStar_UInt32.ml b/engine/backends/fstar/fstar-surface-ast/FStar_UInt32.ml deleted file mode 100644 index d02cd1862..000000000 --- a/engine/backends/fstar/fstar-surface-ast/FStar_UInt32.ml +++ /dev/null @@ -1,105 +0,0 @@ -(* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! *) -(* THIS IS AN AUTOGENERATED FILE! See ulib/ml/Makefile *) -(* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! *) - -(* This file is meant to be concatenated to FStar_Ints.ml.body *) -module M = Stdint.Uint32 -type uint32 = M.t -type t = M.t -let n = Prims.of_int 32 - -let uint_to_t x = M.of_string (Z.to_string x) -let __uint_to_t = uint_to_t -(* This .ml.body file is concatenated to every .ml.prefix file in this - * directory (ulib/ml/) to generate the OCaml realizations for machine - * integers, as they all pretty much share their definitions and are - * based on Stdint. *) - -let v (x:t) : Prims.int = Prims.parse_int (M.to_string x) - -let zero = M.zero -let one = M.one -let ones = M.pred M.zero - -(* Reexport add, plus aliases *) -let add = M.add -let add_underspec = M.add -let add_mod = M.add - -(* Reexport sub, plus aliases *) -let sub = M.sub -let sub_underspec = M.sub -let sub_mod = M.sub - -(* Reexport mul, plus aliases *) -let mul = M.mul -let mul_underspec = M.mul -let mul_mod = M.mul - -(* Conversions to Zarith's int *) -let to_int (x:t) : Z.t = Z.of_string (M.to_string x) -let of_int (x:Z.t) : t = M.of_string (Z.to_string x) - -(* Conversion to native ints; these are potentially unsafe and not part - * of the interface: they are meant to be called only from OCaml code - * that is doing the right thing *) -let of_native_int (x:int) : t = M.of_int x -let to_native_int (x:t) : int = M.to_int x - -(* Just reexport these *) -let div = M.div -let rem = M.rem -let logand = M.logand -let logxor = M.logxor -let logor = M.logor -let lognot = M.lognot -let to_string = M.to_string -let of_string = M.of_string - -let to_string_hex = M.to_string_hex - -let to_string_hex_pad i = - let s0 = M.to_string_hex i in - let len = (String.length s0 - 2) in - let s1 = String.sub s0 2 len in (* Remove leading "0x" *) - let zeroes = String.make ((Z.to_int n / 4) - len) '0' in - zeroes ^ s1 - -(* The shifts take a uint32 argument, so we need to convert *) -let shift_right n i = M.shift_right n (Stdint.Uint32.to_int i) -let shift_left n i = M.shift_left n (Stdint.Uint32.to_int i) -let shift_arithmetic_right = shift_right - -(* Comparison operators *) -let eq (a:t) (b:t) : bool = a = b -let gt (a:t) (b:t) : bool = a > b -let gte (a:t) (b:t) : bool = a >= b -let lt (a:t) (b:t) : bool = a < b -let lte (a:t) (b:t) : bool = a <= b - -(* NOT Constant time operators *) -let eq_mask (a:t) (b:t) : t = if a = b then ones else zero -let gte_mask (a:t) (b:t) : t = if a >= b then ones else zero - -(* Infix notations *) -let op_Plus_Hat = add -let op_Plus_Question_Hat = add_underspec -let op_Plus_Percent_Hat = add_mod -let op_Subtraction_Hat = sub -let op_Subtraction_Question_Hat = sub_underspec -let op_Subtraction_Percent_Hat = sub_mod -let op_Star_Hat = mul -let op_Star_Question_Hat = mul_underspec -let op_Star_Percent_Hat = mul_mod -let op_Slash_Hat = div -let op_Percent_Hat = rem -let op_Hat_Hat = logxor -let op_Amp_Hat = logand -let op_Bar_Hat = logor -let op_Less_Less_Hat = shift_left -let op_Greater_Greater_Hat = shift_right -let op_Equals_Hat = eq -let op_Greater_Hat = gt -let op_Greater_Equals_Hat = gte -let op_Less_Hat = lt -let op_Less_Equals_Hat = lte diff --git a/engine/backends/fstar/fstar-surface-ast/FStar_UInt8.ml b/engine/backends/fstar/fstar-surface-ast/FStar_UInt8.ml deleted file mode 100644 index c0f303c59..000000000 --- a/engine/backends/fstar/fstar-surface-ast/FStar_UInt8.ml +++ /dev/null @@ -1,81 +0,0 @@ -type uint8 = int[@@deriving yojson,show] -type byte = uint8[@@deriving yojson,show] -type t = uint8[@@deriving yojson,show] -type t' = t[@@deriving yojson,show] - -let (%) x y = if x < 0 then (x mod y) + y else x mod y - -let n = Prims.parse_int "8" -let v (x:uint8) : Prims.int = Prims.parse_int (string_of_int x) - -let zero = 0 -let one = 1 -let ones = 255 - -let add (a:uint8) (b:uint8) : uint8 = a + b -let add_underspec a b = (add a b) land 255 -let add_mod = add_underspec - -let sub (a:uint8) (b:uint8) : uint8 = a - b -let sub_underspec a b = (sub a b) land 255 -let sub_mod = sub_underspec - -let mul (a:uint8) (b:uint8) : uint8 = a * b -let mul_underspec a b = (mul a b) land 255 -let mul_mod = mul_underspec - -let div (a:uint8) (b:uint8) : uint8 = a / b - -let rem (a:uint8) (b:uint8) : uint8 = a mod b - -let logand (a:uint8) (b:uint8) : uint8 = a land b -let logxor (a:uint8) (b:uint8) : uint8 = a lxor b -let logor (a:uint8) (b:uint8) : uint8 = a lor b -let lognot (a:uint8) : uint8 = lnot a - -let int_to_uint8 (x:Prims.int) : uint8 = Z.to_int x % 256 - -let shift_right (a:uint8) (b:Stdint.Uint32.t) : uint8 = a lsr (Stdint.Uint32.to_int b) -let shift_left (a:uint8) (b:Stdint.Uint32.t) : uint8 = (a lsl (Stdint.Uint32.to_int b)) land 255 - -(* Comparison operators *) -let eq (a:uint8) (b:uint8) : bool = a = b -let gt (a:uint8) (b:uint8) : bool = a > b -let gte (a:uint8) (b:uint8) : bool = a >= b -let lt (a:uint8) (b:uint8) : bool = a < b -let lte (a:uint8) (b:uint8) : bool = a <= b - -(* NOT Constant time comparison operators *) -let gte_mask (a:uint8) (b:uint8) : uint8 = if a >= b then 255 else 0 -let eq_mask (a:uint8) (b:uint8) : uint8 = if a = b then 255 else 0 - -(* Infix notations *) -let op_Plus_Hat = add -let op_Plus_Question_Hat = add_underspec -let op_Plus_Percent_Hat = add_mod -let op_Subtraction_Hat = sub -let op_Subtraction_Question_Hat = sub_underspec -let op_Subtraction_Percent_Hat = sub_mod -let op_Star_Hat = mul -let op_Star_Question_Hat = mul_underspec -let op_Star_Percent_Hat = mul_mod -let op_Slash_Hat = div -let op_Percent_Hat = rem -let op_Hat_Hat = logxor -let op_Amp_Hat = logand -let op_Bar_Hat = logor -let op_Less_Less_Hat = shift_left -let op_Greater_Greater_Hat = shift_right -let op_Equals_Hat = eq -let op_Greater_Hat = gt -let op_Greater_Equals_Hat = gte -let op_Less_Hat = lt -let op_Less_Equals_Hat = lte - -let of_string s = int_of_string s -let to_string s = string_of_int s -let to_string_hex s = Printf.sprintf "0x%x" s -let to_string_hex_pad s = Printf.sprintf "%02x" s -let uint_to_t s = int_to_uint8 s -let to_int s = s -let __uint_to_t = uint_to_t diff --git a/engine/backends/fstar/fstar-surface-ast/dune b/engine/backends/fstar/fstar-surface-ast/dune index e6b53bab5..5c7c7487a 100644 --- a/engine/backends/fstar/fstar-surface-ast/dune +++ b/engine/backends/fstar/fstar-surface-ast/dune @@ -1,7 +1,7 @@ (library (name fstar_surface_ast) (package hax-engine) - (libraries batteries zarith stdint ppxlib menhirLib pprint) + (libraries batteries stdint ppxlib menhirLib pprint base) (wrapped false) (preprocess (pps ppx_deriving.show ppx_deriving_yojson sedlex.ppx))) diff --git a/engine/backends/fstar/fstar-surface-ast/prims.ml b/engine/backends/fstar/fstar-surface-ast/prims.ml index d8348a1ea..6062e6cd3 100644 --- a/engine/backends/fstar/fstar-surface-ast/prims.ml +++ b/engine/backends/fstar/fstar-surface-ast/prims.ml @@ -12,103 +12,14 @@ let int_of_yojson x = | Ok x -> Ok (parse_int x) | Error x -> Error x -type attribute = unit -let (cps : attribute) = () -type 'Auu____5 hasEq = unit -type eqtype = unit type bool' = bool [@@deriving yojson,show] type bool = bool' [@@deriving yojson,show] -type empty = unit -(*This is how Coq extracts Inductive void := . Our extraction needs to be fixed to recognize when there - are no constructors and generate this type abbreviation*) -type trivial = - | T -let (uu___is_T : trivial -> bool) = fun projectee -> true -type nonrec unit = unit -type 'Ap squash = unit -type 'Ap auto_squash = unit -type l_True = unit -type l_False = unit -type ('Aa,'Ax,'dummyV0) equals = - | Refl -let uu___is_Refl : 'Aa . 'Aa -> 'Aa -> ('Aa,unit,unit) equals -> bool = - fun x -> fun uu____65 -> fun projectee -> true -type ('Aa,'Ax,'Ay) eq2 = unit -type ('Aa,'Ab,'Ax,'Ay) op_Equals_Equals_Equals = unit -type 'Ab b2t = unit -type ('Ap,'Aq) pair = - | Pair of 'Ap * 'Aq -let uu___is_Pair : 'Ap 'Aq . ('Ap,'Aq) pair -> bool = - fun projectee -> true -let __proj__Pair__item___1 : 'Ap 'Aq . ('Ap,'Aq) pair -> 'Ap = - fun projectee -> match projectee with | Pair (_0,_1) -> _0 -let __proj__Pair__item___2 : 'Ap 'Aq . ('Ap,'Aq) pair -> 'Aq = - fun projectee -> match projectee with | Pair (_0,_1) -> _1 -type ('Ap,'Aq) l_and = unit -type ('Ap,'Aq) sum = - | Left of 'Ap - | Right of 'Aq -let uu___is_Left : 'Ap 'Aq . ('Ap,'Aq) sum -> bool = - fun projectee -> - match projectee with | Left _0 -> true | uu____344 -> false -let __proj__Left__item___0 : 'Ap 'Aq . ('Ap,'Aq) sum -> 'Ap = - fun projectee -> match projectee with | Left _0 -> _0 -let uu___is_Right : 'Ap 'Aq . ('Ap,'Aq) sum -> bool = - fun projectee -> - match projectee with | Right _0 -> true | uu____404 -> false - -let __proj__Right__item___0 : 'Ap 'Aq . ('Ap,'Aq) sum -> 'Aq = - fun projectee -> match projectee with | Right _0 -> _0 -type ('Ap,'Aq) l_or = unit -type ('Ap,'Aq) l_imp = unit -type ('Ap,'Aq) l_iff = unit -type 'Ap l_not = unit -type ('Ap,'Aq,'Ar) l_ITE = unit -type ('Aa,'Ab,'Auu____484,'Auu____485) precedes = unit -type ('Aa,'Auu____490,'Auu____491) has_type = unit -type ('Aa,'Ap) l_Forall = unit -type prop = unit -let id x = x -type ('Aa,'Ab) dtuple2 = - | Mkdtuple2 of 'Aa * 'Ab -let uu___is_Mkdtuple2 : 'Aa 'Ab . ('Aa,'Ab) dtuple2 -> bool = - fun projectee -> true -let __proj__Mkdtuple2__item___1 : 'Aa 'Ab . ('Aa,'Ab) dtuple2 -> 'Aa = - fun projectee -> match projectee with | Mkdtuple2 (_1,_2) -> _1 -let __proj__Mkdtuple2__item___2 : 'Aa 'Ab . ('Aa,'Ab) dtuple2 -> 'Ab = - fun projectee -> match projectee with | Mkdtuple2 (_1,_2) -> _2 -type ('Aa,'Ap) l_Exists = unit -type _pos = int * int -type _rng = string * _pos * _pos -type range = _rng * _rng type string' = string[@@deriving yojson,show] type string = string'[@@deriving yojson,show] -type pure_pre = unit -type ('Aa,'Apre) pure_post' = unit -type 'Aa pure_post = unit -type 'Aa pure_wp = unit -type 'Auu____655 guard_free = unit -type ('Aa,'Ax,'Ap) pure_return = unit -type ('Ar1,'Aa,'Ab,'Awp1,'Awp2,'Ap) pure_bind_wp = 'Awp1 -type ('Aa,'Ap,'Awp_then,'Awp_else,'Apost) pure_if_then_else = unit[@@deriving yojson,show] -type ('Aa,'Awp,'Apost) pure_ite_wp = unit -type ('Aa,'Awp1,'Awp2) pure_stronger = unit -type ('Aa,'Ab,'Awp,'Ap) pure_close_wp = unit -type ('Aa,'Aq,'Awp,'Ap) pure_assert_p = unit -type ('Aa,'Aq,'Awp,'Ap) pure_assume_p = unit -type ('Aa,'Ap) pure_null_wp = unit -type ('Aa,'Awp) pure_trivial = 'Awp -type ('Ap, 'Apost) pure_assert_wp = unit -type ('Aa,'Awp,'Auu____878) purewp_id = 'Awp -let mk_range f a b c d : range = let r = (f, (a, b), (c, d)) in (r, r) -let range_0 : range = let z = parse_int "0" in mk_range "" z z z z - -let op_AmpAmp x y = x && y -let op_BarBar x y = x || y let op_Negation x = not x let ( + ) = Z.add @@ -123,80 +34,13 @@ let ( mod ) = Z.erem let ( ~- ) = Z.neg let abs = Z.abs -let op_Multiply x y = x * y -let op_Subtraction x y = x - y -let op_Addition x y = x + y -let op_Minus x = -x -let op_LessThan x y = x < y -let op_LessThanOrEqual x y = x <= y -let op_GreaterThan x y = x > y -let op_GreaterThanOrEqual x y = x >= y -let op_Equality x y = x = y -let op_disEquality x y = x<>y - type nonrec exn = exn -type 'a array' = 'a array[@@deriving yojson,show] -type 'a array = 'a array'[@@deriving yojson,show] -let strcat x y = x ^ y let op_Hat x y = x ^ y type 'a list' = 'a list[@@deriving yojson,show] type 'a list = 'a list'[@@deriving yojson,show] -let uu___is_Nil : 'Aa . 'Aa list -> bool = - fun projectee -> match projectee with | [] -> true | uu____1190 -> false -let uu___is_Cons : 'Aa . 'Aa list -> bool = - fun projectee -> - match projectee with | hd::tl -> true | uu____1216 -> false - -let __proj__Cons__item__hd : 'Aa . 'Aa list -> 'Aa = - fun projectee -> match projectee with | hd::tl -> hd -let __proj__Cons__item__tl : 'Aa . 'Aa list -> 'Aa list = - fun projectee -> match projectee with | hd::tl -> tl -type pattern = unit - - -type ('Aa,'Auu____1278) decreases = unit -let returnM : 'Aa . 'Aa -> 'Aa = fun x -> x -type lex_t = - | LexTop - | LexCons of unit * Obj.t * lex_t -let (uu___is_LexTop : lex_t -> bool) = - fun projectee -> - match projectee with | LexTop -> true | uu____1313 -> false - -let (uu___is_LexCons : lex_t -> bool) = - fun projectee -> - match projectee with | LexCons (a,_1,_2) -> true | uu____1327 -> false - -type 'Aprojectee __proj__LexCons__item__a = Obj.t -let (__proj__LexCons__item___1 : lex_t -> Obj.t) = - fun projectee -> match projectee with | LexCons (a,_1,_2) -> _1 -let (__proj__LexCons__item___2 : lex_t -> lex_t) = - fun projectee -> match projectee with | LexCons (a,_1,_2) -> _2 -type ('Aa,'Awp) as_requires = 'Awp -type ('Aa,'Awp,'Ax) as_ensures = unit -let admit () = failwith "Prims.admit: cannot be executed" -let magic () = failwith "Prims.magic: cannot be executed" -let unsafe_coerce : 'Aa 'Ab . 'Aa -> 'Ab = - fun x -> Obj.magic x - -type 'Ap spinoff = 'Ap - type nat = int type pos = int -type nonzero = int -let op_Modulus x y = x mod y -let op_Division x y = x / y -let rec (pow2 : nat -> pos) = - fun x -> - Z.shift_left Z.one (Z.to_int x) - -let (min : int -> int -> int) = - fun x -> fun y -> if x <= y then x else y -let (abs : int -> int) = - fun x -> if x >= (parse_int "0") then x else op_Minus x let string_of_bool = string_of_bool let string_of_int = to_string - -type ('Ar,'Amsg,'Ab) labeled = 'Ab diff --git a/engine/backends/fstar/fstar-surface-ast/z.ml b/engine/backends/fstar/fstar-surface-ast/z.ml new file mode 100644 index 000000000..e30361527 --- /dev/null +++ b/engine/backends/fstar/fstar-surface-ast/z.ml @@ -0,0 +1,38 @@ +type t = String.t [@@deriving show] + +let to_t = Base.Int.of_string +let of_t = Base.Int.to_string + +let compare = String.compare +let pp_print = pp +let hash = Base.String.hash + + +let to_int: String.t -> Base.Int.t = Base.Int.of_string +let of_int: Base.Int.t -> String.t = Base.Int.to_string + + +let zero: String.t = "0" +let one: String.t = "1" +let of_string x = x +let to_string x = x + +open struct + let map (f: int -> int): string -> string = fun s -> Base.Int.of_string s |> f |> Base.Int.to_string + let map2 (f: int -> int -> int): string -> string -> string = fun x y -> f (Base.Int.of_string x) (Base.Int.of_string y) |> Base.Int.to_string + let map2' (f: int -> int -> 'a): string -> string -> 'a = fun x y -> f (Base.Int.of_string x) (Base.Int.of_string y) + end + +let add = map2 ( + ) +let sub = map2 ( - ) +let mul = map2 ( * ) +let ediv = map2 ( / ) +let leq = map2' ( <= ) +let geq = map2' ( >= ) +let lt = map2' ( < ) +let gt = map2' ( > ) +let erem = map2 Base.Int.( % ) +let neg = map Base.Int.neg +let abs = map abs +let shift_left: string -> Base.Int.t -> string = fun x i -> Base.Int.shift_left (Base.Int.of_string x) i |> Base.Int.to_string +let shift_right: string -> Base.Int.t -> string = fun x i -> Base.Int.shift_right (Base.Int.of_string x) i |> Base.Int.to_string diff --git a/engine/backends/fstar/fstar_ast.ml b/engine/backends/fstar/fstar_ast.ml index 2352ae732..0ead59bd5 100644 --- a/engine/backends/fstar/fstar_ast.ml +++ b/engine/backends/fstar/fstar_ast.ml @@ -35,6 +35,7 @@ module Attrs = struct end let tcresolve = term @@ AST.Var FStar_Parser_Const.tcresolve_lid +let solve = term @@ AST.Var FStar_Parser_Const.solve_lid let pat_var_tcresolve (var : string option) = let tcresolve = Some (AST.Meta tcresolve) in @@ -116,3 +117,4 @@ let decl_of_string s = match decls_of_string s with [ d ] -> d | _ -> failwith "decl_of_string" let ascribe t e = term @@ AST.Ascribed (e, t, None, false) +let implies p q = AST.Op (id "==>", [ p; q ]) |> term diff --git a/engine/backends/fstar/fstar_backend.ml b/engine/backends/fstar/fstar_backend.ml index 2ec0f58d8..d1238dce8 100644 --- a/engine/backends/fstar/fstar_backend.ml +++ b/engine/backends/fstar/fstar_backend.ml @@ -12,6 +12,7 @@ include include On.Macro include On.Construct_base include On.Quote + include On.Dyn end) (struct let backend = Diagnostics.Backend.FStar @@ -39,7 +40,9 @@ module SubtypeToInputLanguage and type for_loop = Features.Off.for_loop and type while_loop = Features.Off.while_loop and type for_index_loop = Features.Off.for_index_loop - and type state_passing_loop = Features.Off.state_passing_loop) = + and type state_passing_loop = Features.Off.state_passing_loop + and type match_guard = Features.Off.match_guard + and type trait_item_default = Features.Off.trait_item_default) = struct module FB = InputLanguage @@ -54,6 +57,7 @@ struct include Features.SUBTYPE.On.Slice include Features.SUBTYPE.On.Macro include Features.SUBTYPE.On.Quote + include Features.SUBTYPE.On.Dyn end) let metadata = Phase_utils.Metadata.make (Reject (NotInBackendLang backend)) @@ -74,7 +78,7 @@ module FStarNamePolicy = struct let index_field_transform index = "_" ^ index - let reserved_words = Hash_set.of_list (module String) ["attributes";"noeq";"unopteq";"and";"assert";"assume";"begin";"by";"calc";"class";"default";"decreases";"effect";"eliminate";"else";"end";"ensures";"exception";"exists";"false";"friend";"forall";"fun";"λ";"function";"if";"in";"include";"inline";"inline_for_extraction";"instance";"introduce";"irreducible";"let";"logic";"match";"returns";"as";"module";"new";"new_effect";"layered_effect";"polymonadic_bind";"polymonadic_subcomp";"noextract";"of";"open";"opaque";"private";"quote";"range_of";"rec";"reifiable";"reify";"reflectable";"requires";"set_range_of";"sub_effect";"synth";"then";"total";"true";"try";"type";"unfold";"unfoldable";"val";"when";"with";"_";"__SOURCE_FILE__";"__LINE__";"match";"if";"let";"and"] + let reserved_words = Hash_set.of_list (module String) ["attributes";"noeq";"unopteq";"and";"assert";"assume";"begin";"by";"calc";"class";"default";"decreases";"effect";"eliminate";"else";"end";"ensures";"exception";"exists";"false";"friend";"forall";"fun";"λ";"function";"if";"in";"include";"inline";"inline_for_extraction";"instance";"introduce";"irreducible";"let";"logic";"match";"returns";"as";"module";"new";"new_effect";"layered_effect";"polymonadic_bind";"polymonadic_subcomp";"noextract";"of";"open";"opaque";"private";"quote";"range_of";"rec";"reifiable";"reify";"reflectable";"requires";"set_range_of";"sub_effect";"synth";"then";"total";"true";"try";"type";"unfold";"unfoldable";"val";"when";"with";"_";"__SOURCE_FILE__";"__LINE__";"match";"if";"let";"and";"string"] end module U = Ast_utils.MakeWithNamePolicy (InputLanguage) (FStarNamePolicy) @@ -82,23 +86,12 @@ module Visitors = Ast_visitors.Make (InputLanguage) open AST module F = Fstar_ast -let doc_to_string : PPrint.document -> string = - FStar_Pprint.pretty_string 1.0 (Z.of_int 100) - -let term_to_string : F.AST.term -> string = - FStar_Parser_ToDocument.term_to_document >> doc_to_string - -let pat_to_string : F.AST.pattern -> string = - FStar_Parser_ToDocument.pat_to_document >> doc_to_string - -let decl_to_string : F.AST.decl -> string = - FStar_Parser_ToDocument.decl_to_document >> doc_to_string - module Context = struct type t = { current_namespace : string * string list; items : item list; interface_mode : bool; + line_width : int; } end @@ -109,6 +102,18 @@ module Make struct open Ctx + let doc_to_string : PPrint.document -> string = + FStar_Pprint.pretty_string 1.0 (Z.of_int ctx.line_width) + + let term_to_string : F.AST.term -> string = + FStar_Parser_ToDocument.term_to_document >> doc_to_string + + let pat_to_string : F.AST.pattern -> string = + FStar_Parser_ToDocument.pat_to_document >> doc_to_string + + let decl_to_string : F.AST.decl -> string = + FStar_Parser_ToDocument.decl_to_document >> doc_to_string + let pprim_ident (span : span) (id : primitive_ident) = match id with | Deref -> Error.assertion_failure span "pprim_ident Deref" @@ -311,8 +316,28 @@ struct (impl, F.lid [ U.Concrete_ident_view.to_definition_name item ]) | None -> F.term @@ F.AST.Wild) | TOpaque s -> F.term @@ F.AST.Wild + | TDyn { goals; _ } -> + let traits = List.map ~f:(pdyn_trait_goal span) goals in + let dyn = F.AST.Var (F.lid [ "dyn" ]) |> F.term in + let length = + F.AST.Const + (FStar_Const.Const_int (List.length goals |> Int.to_string, None)) + |> F.term + in + F.mk_e_app dyn (length :: traits) | _ -> . + and pdyn_trait_goal span (goal : dyn_trait_goal) = + (* This introduces a potential shadowing *) + let type_var = "z" in + let pat = F.pat @@ F.AST.PatVar (F.id type_var, None, []) in + let trait = F.AST.Var (pconcrete_ident goal.trait) |> F.term in + let args = + (F.AST.Var (F.lid [ type_var ]) |> F.term) + :: List.map ~f:(pgeneric_value span) goal.non_self_args + in + F.mk_e_abs [ pat ] (F.mk_e_app trait args) + and pimpl_expr span (ie : impl_expr) = let some = Option.some in let hax_unstable_impl_exprs = false in @@ -407,6 +432,26 @@ struct (* in *) F.term @@ F.AST.Const (F.Const.Const_string ("failure", F.dummyRange)) + and fun_application ~span f args ~trait_generic_args ~generic_args = + let pgeneric_args ?qualifier = + let qualifier_or default = Option.value ~default qualifier in + List.filter ~f:(function GType (TArrow _) -> false | _ -> true) + >> List.map ~f:(function + | GConst const -> (pexpr const, qualifier_or F.AST.Nothing) + | GLifetime _ -> . + | GType ty -> (pty span ty, qualifier_or F.AST.Hash)) + in + let args = List.map ~f:(pexpr &&& Fn.const F.AST.Nothing) args in + let trait_generic_args = + Option.map + ~f: + (pgeneric_args ~qualifier:F.AST.Hash + >> Fn.flip ( @ ) [ (F.solve, F.AST.Hash) ]) + trait_generic_args + |> Option.value ~default:[] + in + F.mk_app f (trait_generic_args @ pgeneric_args generic_args @ args) + and pexpr_unwrapped (e : expr) = match e.e with | Literal l -> pliteral_as_expr e.span l @@ -437,7 +482,7 @@ struct { f = { e = GlobalVar f; _ }; args = [ { e = Literal (String s); _ } ]; - generic_args; + generic_args = _; } when Global_ident.eq_name Hax_lib__int__Impl_5___unsafe_from_str f -> (match @@ -451,17 +496,10 @@ struct @@ "pexpr: expected a integer, found the following non-digit \ chars: '" ^ s ^ "'"); F.AST.Const (F.Const.Const_int (s, None)) |> F.term - | App { f; args; generic_args; bounds_impls = _; impl = _ } -> - let generic_args = - generic_args - |> List.filter ~f:(function GType (TArrow _) -> false | _ -> true) - |> List.map ~f:(function - | GConst const -> (pexpr const, F.AST.Nothing) - | GLifetime _ -> . - | GType ty -> (pty e.span ty, F.AST.Hash)) - in - let args = List.map ~f:(pexpr &&& Fn.const F.AST.Nothing) args in - F.mk_app (pexpr f) (generic_args @ args) + | App { f; args; generic_args; bounds_impls = _; trait } -> + let trait_generic_args = Option.map ~f:snd trait in + fun_application (pexpr f) args ~span:e.span ~trait_generic_args + ~generic_args | If { cond; then_; else_ } -> F.term @@ F.AST.If @@ -626,12 +664,16 @@ struct type kind = Implicit | Tcresolve | Explicit type t = { kind : kind; ident : F.Ident.ident; typ : F.AST.term } - let of_generic_param ?(kind : kind = Implicit) span (p : generic_param) : t - = + let make_explicit x = { x with kind = Explicit } + + let implicit_to_explicit x = + if [%matches? Tcresolve] x.kind then x else make_explicit x + + let of_generic_param span (p : generic_param) : t = let ident = plocal_ident p.ident in match p.kind with | GPLifetime _ -> Error.assertion_failure span "pgeneric_param:LIFETIME" - | GPType { default = _ } -> { kind; typ = F.type0_term; ident } + | GPType { default = _ } -> { kind = Implicit; typ = F.type0_term; ident } | GPConst { typ } -> { kind = Explicit; typ = pty span typ; ident } let of_generic_constraint span (nth : int) (c : generic_constraint) = @@ -639,16 +681,27 @@ struct | GCLifetime _ -> . | GCType { goal; name } -> let typ = c_trait_goal span goal in - { kind = Tcresolve; ident = F.id name; typ } + Some { kind = Tcresolve; ident = F.id name; typ } + | GCProjection _ -> + (* TODO: Not yet implemented, see https://github.com/hacspec/hax/issues/785 *) + None - let of_generics ?(kind : kind = Implicit) span generics : t list = - List.map ~f:(of_generic_param ~kind span) generics.params - @ List.mapi ~f:(of_generic_constraint span) generics.constraints + let of_generics span generics : t list = + List.map ~f:(of_generic_param span) generics.params + @ List.filter_mapi ~f:(of_generic_constraint span) generics.constraints let of_typ span (nth : int) typ : t = let ident = F.id ("x" ^ Int.to_string nth) in { kind = Explicit; ident; typ = pty span typ } + (** Makes an F* binder from a name and an F* type *) + let of_named_fstar_typ span name typ : t = + let ident = plocal_ident name in + { kind = Explicit; ident; typ } + + (** Makes an F* binder from a name and an hax type *) + let of_named_typ span name = pty span >> of_named_fstar_typ span name + let to_pattern (x : t) : F.AST.pattern = let subpat = match x.kind with @@ -673,17 +726,24 @@ struct let to_term (x : t) : F.AST.term = F.term @@ F.AST.Var (FStar_Ident.lid_of_ns_and_id [] (to_ident x)) + let to_imp (x : t) : F.AST.imp = + match x.kind with Tcresolve | Implicit -> Hash | Explicit -> Nothing + + let to_qualified_term : t -> F.AST.term * F.AST.imp = to_term &&& to_imp + + let to_qualifier (x : t) : F.AST.arg_qualifier option = + match x.kind with + | Tcresolve -> Some TypeClassArg + | Implicit -> Some Implicit + | Explicit -> None + let to_binder (x : t) : F.AST.binder = F.AST. { b = F.AST.Annotated (x.ident, x.typ); brange = F.dummyRange; blevel = Un; - aqual = - (match x.kind with - | Tcresolve -> Some TypeClassArg - | Implicit -> Some Implicit - | Explicit -> None); + aqual = to_qualifier x; battributes = []; } end @@ -694,90 +754,9 @@ struct Error.assertion_failure span "pgeneric_constraint_bd:LIFETIME" | GCType { goal; name = _ } -> c_trait_goal span goal - let get_attr (type a) (name : string) (map : string -> a) (attrs : attrs) : - a option = - List.find_map - ~f:(fun attr -> - match attr.kind with - | Tool { path; tokens } when [%eq: string] path name -> - Some (map tokens) - | _ -> None) - attrs - - module UUID : sig - type t - - val of_attrs : attrs -> t option - val associated_items : ?kind:string -> t option -> item list - val associated_item : ?kind:string -> t option -> item option - end = struct - (* TODO: parse_quoted_string is incorrect *) - let parse_quoted_string = String.strip ~drop:([%eq: char] '"') - - let parse_associated_with s = - let uuid, kind = String.lsplit2 ~on:',' s |> Option.value_exn in - let uuid = parse_quoted_string uuid in - let kind = String.strip ~drop:([%eq: char] ' ') kind in - (uuid, kind) - - type t = string - - let of_attrs : attrs -> t option = get_attr "_hax::uuid" parse_quoted_string - - let associated_items ?kind (uuid : t option) : item list = - let ( let* ) x f = Option.bind ~f x in - Option.value ~default:[] - (let* uuid = uuid in - List.filter - ~f:(fun item -> - Option.value ~default:false - (let* uuid', kind' = - get_attr "_hax::associated_with" parse_associated_with - item.attrs - in - let kind_eq = - match kind with - | Some kind -> String.equal kind' kind - | None -> true - in - Some (kind_eq && String.equal uuid' uuid))) - ctx.items - |> Option.some) - - let associated_item ?kind (uuid : t option) : item option = - match associated_items ?kind uuid with - | [ i ] -> Some i - | [] -> None - | _ -> failwith "expected 0-1 items" - end - - (* TODO: incorrect *) - let fvar_of_params = function - | { pat = { p = PBinding { var; _ }; _ }; _ } -> var - | _ -> failwith "?? todo" - - let associated_refinement (free_variables : string list) (attrs : attrs) : - expr option = - UUID.associated_item ~kind:"refinement" (UUID.of_attrs attrs) - |> Option.map ~f:(function - | { v = Fn { params; body; _ }; _ } -> - let substs = - List.zip_exn - (List.map ~f:fvar_of_params params) - (List.map ~f:Local_ident.make_final free_variables) - in - let v = - U.Mappers.rename_local_idents (fun i -> - match List.find ~f:(fst >> [%eq: local_ident] i) substs with - | None -> i - | Some (_, i) -> i) - in - v#visit_expr () body - | _ -> failwith "expected associated_refinement") - let pmaybe_refined_ty span (free_variables : string list) (attrs : attrs) (binder_name : string) (ty : ty) : F.AST.term = - match Attrs.associated_refinement_in_type free_variables attrs with + match Attrs.associated_refinement_in_type span free_variables attrs with | Some refinement -> F.mk_refined binder_name (pty span ty) (fun ~x -> pexpr refinement) | None -> pty span ty @@ -1011,7 +990,8 @@ struct [ F.AST.TyconRecord ( F.id @@ U.Concrete_ident_view.to_definition_name name, - FStarBinder.of_generics ~kind:Explicit e.span generics + FStarBinder.of_generics e.span generics + |> List.map ~f:FStarBinder.implicit_to_explicit |> List.map ~f:FStarBinder.to_binder, None, [], @@ -1077,7 +1057,8 @@ struct [ F.AST.TyconVariant ( F.id @@ U.Concrete_ident_view.to_definition_name name, - FStarBinder.of_generics ~kind:Explicit e.span generics + FStarBinder.of_generics e.span generics + |> List.map ~f:FStarBinder.implicit_to_explicit |> List.map ~f:FStarBinder.to_binder, None, constructors ); @@ -1154,20 +1135,13 @@ struct | _ -> unsupported_macro ()) | _ -> unsupported_macro ()) | Trait { name; generics; items } -> - let bds = - List.map - ~f:FStarBinder.(of_generic_param ~kind:Explicit e.span >> to_binder) - generics.params - in let name_str = U.Concrete_ident_view.to_definition_name name in let name_id = F.id @@ name_str in let fields = List.concat_map ~f:(fun i -> let name = U.Concrete_ident_view.to_definition_name i.ti_ident in - let generics = - FStarBinder.of_generics ~kind:Implicit i.ti_span i.ti_generics - in + let generics = FStarBinder.of_generics i.ti_span i.ti_generics in let bds = generics |> List.map ~f:FStarBinder.to_binder in let fields = match i.ti_v with @@ -1198,25 +1172,154 @@ struct [], F.mk_e_app base args )) bounds - | TIFn (TArrow (inputs, output)) + | TIFn ty when Attrs.find_unique_attr i.ti_attrs ~f:(function | TraitMethodNoPrePost -> Some () | _ -> None) - |> Option.is_none -> + |> Option.is_some -> + let weakest = + let h kind = + Attrs.associated_fns kind i.ti_attrs + |> List.hd + |> Option.map ~f:(fun attr -> + ( attr, + [%eq: Attr_payloads.AssocRole.t] kind Requires + )) + in + Option.first_some (h Ensures) (h Requires) + |> Option.map + ~f:(fun ((generics, params, expr), is_req) -> + let dummy_self = + List.find generics.params + ~f:[%matches? { kind = GPType _; _ }] + |> Option.value_or_thunk ~default:(fun () -> + Error.assertion_failure i.ti_span + ("Expected a first generic of type \ + `Self`. Instead generics params \ + are: " + ^ [%show: generic_param list] + generics.params)) + |> fun x -> x.ident + in + let self = + Local_ident.{ name = "Self"; id = mk_id Typ 0 } + in + let renamer = + let f (id : local_ident) = + if [%eq: string] dummy_self.name id.name then + self + else id + in + U.Mappers.rename_local_idents f + in + let generics = + renamer#visit_generics () generics + in + let params = + List.map ~f:(renamer#visit_param ()) params + in + let expr = renamer#visit_expr () expr in + (generics, params, expr, is_req)) + in + let ty = + let variables = + let idents_visitor = U.Reducers.collect_local_idents in + idents_visitor#visit_trait_item () i + :: (Option.map + ~f:(fun (generics, params, expr, _) -> + [ + idents_visitor#visit_generics () generics; + idents_visitor#visit_expr () expr; + ] + @ List.map + ~f:(idents_visitor#visit_param ()) + params) + weakest + |> Option.value ~default:[]) + |> Set.union_list (module Local_ident) + |> Set.to_list |> ref + in + let mk_fresh prefix = + let v = U.fresh_local_ident_in !variables prefix in + variables := v :: !variables; + v + in + let bindings = ref [] in + let f (p : param) = + let name = + match p.pat.p with + | PBinding { var; _ } -> var + | _ -> + let name = mk_fresh "x" in + let ({ span; typ; _ } : pat) = p.pat in + let expr = { e = LocalVar name; span; typ } in + bindings := (p.pat, expr) :: !bindings; + name + in + FStarBinder.of_named_typ p.pat.span name p.typ + in + weakest + |> Option.map ~f:(fun (generics, binders, expr, is_req) -> + (generics, List.map ~f binders, expr, is_req)) + |> Option.map + ~f:(fun (generics, binders, (expr : expr), is_req) -> + let result_ident = mk_fresh "pred" in + let result_bd = + FStarBinder.of_named_fstar_typ expr.span + result_ident F.type0_term + in + let expr = U.make_lets !bindings expr in + let expr = pexpr expr in + let result = + F.term + @@ F.AST.Var + (plocal_ident result_ident |> F.lid_of_id) + in + let result = + F.AST.Refine + ( FStarBinder.to_binder result_bd, + (if is_req then Fn.flip else Fn.id) + F.implies result expr ) + |> F.term + in + F.AST.Product + ( List.map ~f:FStarBinder.to_binder binders, + result ) + |> F.term) + |> Option.value_or_thunk ~default:(fun _ -> + let ty = pty e.span ty in + match ty.tm with + | F.AST.Product (inputs, _) -> + { + ty with + tm = F.AST.Product (inputs, F.type0_term); + } + | _ -> F.type0_term) + in + + let ty = + F.term + @@ F.AST.Product + (generics |> List.map ~f:FStarBinder.to_binder, ty) + in + [ (F.id name, None, [], ty) ] + | TIFn (TArrow (inputs, output)) -> let inputs = List.mapi ~f:(FStarBinder.of_typ e.span) inputs in let inputs = generics @ inputs in let output = pty e.span output in let ty_pre_post = - let inputs = List.map ~f:FStarBinder.to_term inputs in + let inputs = + List.map ~f:FStarBinder.to_qualified_term inputs + in let add_pre n = n ^ "_pre" in let pre_name_str = U.Concrete_ident_view.to_definition_name (Concrete_ident.Create.map_last ~f:add_pre i.ti_ident) in let pre = - F.mk_e_app (F.term_of_lid [ pre_name_str ]) inputs + F.mk_app (F.term_of_lid [ pre_name_str ]) inputs in let result = F.term_of_lid [ "result" ] in let add_post n = n ^ "_post" in @@ -1225,9 +1328,9 @@ struct (Concrete_ident.Create.map_last ~f:add_post i.ti_ident) in let post = - F.mk_e_app + F.mk_app (F.term_of_lid [ post_name_str ]) - (inputs @ [ result ]) + (inputs @ [ (result, Nothing) ]) in let post = F.mk_e_abs @@ -1241,14 +1344,13 @@ struct let inputs = List.map ~f:FStarBinder.to_binder inputs in let ty = F.term @@ F.AST.Product (inputs, ty_pre_post) in [ (F.id name, None, [], ty) ] - | TIFn ty -> - let ty = pty e.span ty in - let ty = - F.term - @@ F.AST.Product - (generics |> List.map ~f:FStarBinder.to_binder, ty) - in + | TIFn non_arrow_ty -> + let inputs = generics in + let output = pty e.span non_arrow_ty in + let inputs = List.map ~f:FStarBinder.to_binder inputs in + let ty = F.term @@ F.AST.Product (inputs, output) in [ (F.id name, None, [], ty) ] + | _ -> . in List.map ~f:Fn.id (* ~f:(fun (n, q, a, ty) -> (n, q, a, F.mk_e_app bds ty)) *) @@ -1257,13 +1359,16 @@ struct in let constraints_fields : FStar_Parser_AST.tycon_record = generics.constraints - |> List.map ~f:(fun c -> - let bound, id = - match c with GCType { goal; name } -> (goal, name) | _ -> . - in - let name = "_super_" ^ id in - let typ = pgeneric_constraint_type e.span c in - (F.id name, None, [ F.Attrs.no_method ], typ)) + |> List.filter_map ~f:(fun c -> + match c with + | GCType { goal = bound; name = id } -> + let name = "_super_" ^ id in + let typ = pgeneric_constraint_type e.span c in + Some (F.id name, None, [ F.Attrs.no_method ], typ) + | GCProjection _ -> + (* TODO: Not yet implemented, see https://github.com/hacspec/hax/issues/785 *) + None + | _ -> .) in let fields : FStar_Parser_AST.tycon_record = constraints_fields @ fields @@ -1274,7 +1379,17 @@ struct [ (F.id marker_field, None, [], pty e.span U.unit_typ) ] else fields in - let tcdef = F.AST.TyconRecord (name_id, bds, None, [], fields) in + let tcdef = + (* Binders are explicit on class definitions *) + let bds = + List.map + ~f: + FStarBinder.( + of_generic_param e.span >> implicit_to_explicit >> to_binder) + generics.params + in + F.AST.TyconRecord (name_id, bds, None, [], fields) + in let d = F.AST.Tycon (false, true, [ tcdef ]) in [ `Intf { d; drange = F.dummyRange; quals = []; attrs = [] } ] | Impl @@ -1348,15 +1463,13 @@ struct |> Option.value_or_thunk ~default:(fun _ -> Error.assertion_failure e.span "Malformed `Quote` item: could not find a ItemQuote payload") - |> Option.value ~default:Types.{ intf = true; impl = false } + |> Option.value ~default:Types.{ intf = false; impl = true } in - (if fstar_opts.intf then - [ `VerbatimIntf (pquote e.span quote, `Newline) ] - else []) - @ - if fstar_opts.impl then - [ `VerbatimImpl (pquote e.span quote, `Newline) ] - else [] + let payload = (pquote e.span quote, `Newline) in + if ctx.interface_mode then + (if fstar_opts.intf then [ `VerbatimIntf payload ] else []) + @ if fstar_opts.impl then [ `VerbatimImpl payload ] else [] + else [ `VerbatimImpl payload ] | HaxError details -> [ `Comment @@ -1368,6 +1481,8 @@ struct end module type S = sig + val decl_to_string : F.AST.decl -> string + val pitem : item -> [> `Impl of F.AST.decl @@ -1413,6 +1528,7 @@ let strings_of_item ~signature_only (bo : BackendOptions.t) m items current_namespace = U.Concrete_ident_view.to_namespace item.ident; interface_mode; items; + line_width = bo.line_width; } in let mk_impl = if interface_mode then fun i -> `Impl i else fun i -> `Impl i in @@ -1424,8 +1540,8 @@ let strings_of_item ~signature_only (bo : BackendOptions.t) m items Print.pitem item |> List.filter ~f:(function `Impl _ when no_impl -> false | _ -> true) |> List.concat_map ~f:(function - | `Impl i -> [ (mk_impl (decl_to_string i), `Newline) ] - | `Intf i -> [ (mk_intf (decl_to_string i), `Newline) ] + | `Impl i -> [ (mk_impl (Print.decl_to_string i), `Newline) ] + | `Intf i -> [ (mk_intf (Print.decl_to_string i), `Newline) ] | `VerbatimIntf (s, nl) -> [ ((if interface_mode then `Intf s else `Impl s), nl) ] | `VerbatimImpl (s, nl) -> @@ -1510,8 +1626,12 @@ let string_of_items ~signature_only ~mod_name (bo : BackendOptions.t) m items : in match lines with [] -> "" | _ -> header ^ String.concat ~sep:"\n" lines in - ( string_for (function `Impl s -> Some s | _ -> None), - string_for (function `Intf s -> Some s | _ -> None) ) + let replace = + String.substr_replace_all ~pattern:"_hax_panic_freedom_admit_" + ~with_:"admit () (* Panic freedom *)" + in + ( string_for (function `Impl s -> Some (replace s) | _ -> None), + string_for (function `Intf s -> Some (replace s) | _ -> None) ) let fstar_headers (bo : BackendOptions.t) = let opts = @@ -1569,14 +1689,17 @@ module TransformToInputLanguage = |> Phases.Drop_sized_trait |> Phases.Simplify_question_marks |> Phases.And_mut_defsite + |> Phases.Reconstruct_asserts |> Phases.Reconstruct_for_loops |> Phases.Reconstruct_while_loops |> Phases.Direct_and_mut |> Phases.Reject.Arbitrary_lhs |> Phases.Drop_blocks + |> Phases.Drop_match_guards |> Phases.Drop_references |> Phases.Trivialize_assign_lhs |> Side_effect_utils.Hoist + |> Phases.Hoist_disjunctive_patterns |> Phases.Simplify_match_return |> Phases.Drop_needless_returns |> Phases.Local_mutation @@ -1588,11 +1711,36 @@ module TransformToInputLanguage = |> Phases.Traits_specs |> Phases.Simplify_hoisting |> Phases.Newtype_as_refinement + |> Phases.Reject.Trait_item_default |> SubtypeToInputLanguage |> Identity ] [@ocamlformat "disable"] +(** Rewrites `unsize x` to `x <: τ` when `τ` is in the allowlist described by `unsize_identity_typ` *) +let unsize_as_identity = + (* Tells if a unsize should be treated as identity by type *) + let rec unsize_identity_typ = function + | TArray _ -> true + | TRef { typ; _ } -> unsize_identity_typ typ + | _ -> false + in + let visitor = + object + inherit [_] U.Visitors.map as super + + method! visit_expr () e = + match e.e with + | App { f = { e = GlobalVar f; _ }; args = [ x ]; _ } + when Global_ident.eq_name Rust_primitives__unsize f + && unsize_identity_typ x.typ -> + let x = super#visit_expr () x in + { e with e = Ascription { e = x; typ = e.typ } } + | _ -> super#visit_expr () e + end + in + visitor#visit_item () + let apply_phases (bo : BackendOptions.t) (items : Ast.Rust.item list) : AST.item list = let items = @@ -1610,6 +1758,8 @@ let apply_phases (bo : BackendOptions.t) (items : Ast.Rust.item list) : in let items = TransformToInputLanguage.ditems items + |> List.map ~f:unsize_as_identity + |> List.map ~f:unsize_as_identity |> List.map ~f:U.Mappers.add_typ_ascription (* |> DepGraph.name_me *) in diff --git a/engine/backends/proverif/proverif_backend.ml b/engine/backends/proverif/proverif_backend.ml index 4c19dbadf..50aaaea82 100644 --- a/engine/backends/proverif/proverif_backend.ml +++ b/engine/backends/proverif/proverif_backend.ml @@ -83,6 +83,9 @@ struct let monadic_action = reject let monadic_binding = reject let block = reject + let dyn = reject + let match_guard = reject + let trait_item_default = reject let metadata = Phase_reject.make_metadata (NotInBackendLang ProVerif) end) @@ -928,9 +931,10 @@ module TransformToInputLanguage = |> Phases.Simplify_match_return |> Phases.Drop_needless_returns |> Phases.Local_mutation - |> Phases.Reject.Continue - |> ProVerifRename - |> SubtypeToInputLanguage + |> Phases.Reject.Continue + |> Phases.Reject.Dyn + |> ProVerifRename + |> SubtypeToInputLanguage |> Identity ] [@ocamlformat "disable"] diff --git a/engine/bin/dune-js b/engine/bin/dune-js index 68df628e7..ac3327c05 100644 --- a/engine/bin/dune-js +++ b/engine/bin/dune-js @@ -5,4 +5,4 @@ (modules js_driver) (js_of_ocaml (javascript_files js_stubs/mutex.js js_stubs/stdint.js js_stubs/unix.js)) - (libraries zarith_stubs_js js_of_ocaml lib)) + (libraries js_of_ocaml lib)) diff --git a/engine/bin/js_driver.ml b/engine/bin/js_driver.ml index 0030ada16..ce0ad7a7e 100644 --- a/engine/bin/js_driver.ml +++ b/engine/bin/js_driver.ml @@ -82,4 +82,17 @@ let yojson_of_string_via_js (s : string) : Yojson.Safe.t = in fun_call fn [| string s |> coerce |] |> Obj.magic -let _ = Lib.main (Lib.read_options_from_stdin yojson_of_string_via_js) +let _ = + Hax_engine.Hax_io.init + (module struct + let read_json () = + let line = Stdio.In_channel.input_line Stdio.In_channel.stdin in + Option.map ~f:yojson_of_string_via_js line + + let write_json msg = + let open Stdio.Out_channel in + Yojson.Safe.to_channel stdout msg; + output_char stdout '\n'; + flush stdout + end); + Lib.main () diff --git a/engine/bin/lib.ml b/engine/bin/lib.ml index b97fdd7b3..ae601a8e9 100644 --- a/engine/bin/lib.ml +++ b/engine/bin/lib.ml @@ -2,11 +2,6 @@ open Hax_engine open Base open Stdio -let read_options_from_stdin (yojson_from_string : string -> Yojson.Safe.t) : - Types.engine_options = - In_channel.input_all In_channel.stdin - |> yojson_from_string |> Types.parse_engine_options - let setup_logs (options : Types.engine_options) = let level : Logs.level option = match options.backend.verbose with @@ -94,6 +89,13 @@ let run (options : Types.engine_options) : Types.output = options.backend.translation_options.include_namespaces in let items = import_thir_items include_clauses options.input in + let items = + if options.backend.extract_type_aliases then items + else + List.filter + ~f:(function { v = TyAlias _; _ } -> false | _ -> true) + items + in Logs.info (fun m -> m "Applying phase for backend %s" ([%show: Diagnostics.Backend.t] M.backend)); @@ -124,7 +126,11 @@ let run (options : Types.engine_options) : Types.output = debug_json = None; } -let main (options : Types.engine_options) = +(** Entrypoint of the engine. Assumes `Hax_io.init` was called. *) +let main () = + let options = + Hax_io.read_json () |> Option.value_exn |> Types.parse_engine_options + in Printexc.record_backtrace true; let result = try Ok (run options) with @@ -142,8 +148,15 @@ let main (options : Types.engine_options) = let debug_json = Phase_utils.DebugBindPhase.export () in let results = { results with debug_json } in Logs.info (fun m -> m "Outputting JSON"); - Types.to_json_output results - |> Yojson.Safe.pretty_to_string |> print_endline; + + List.iter + ~f:(fun diag -> Diagnostic diag |> Hax_io.write) + results.diagnostics; + List.iter ~f:(fun file -> File file |> Hax_io.write) results.files; + + Option.iter ~f:(fun json -> DebugString json |> Hax_io.write) debug_json; + Hax_io.close (); + Logs.info (fun m -> m "Exiting Hax engine (success)") | Error (exn, bt) -> Logs.info (fun m -> m "Exiting Hax engine (with an unexpected failure)"); diff --git a/engine/bin/lib.mli b/engine/bin/lib.mli index 4311817b8..86f37aa4f 100644 --- a/engine/bin/lib.mli +++ b/engine/bin/lib.mli @@ -1,4 +1 @@ -val read_options_from_stdin : - (string -> Yojson.Safe.t) -> Hax_engine.Types.engine_options - -val main : Hax_engine.Types.engine_options -> unit +val main : unit -> unit diff --git a/engine/bin/native_driver.ml b/engine/bin/native_driver.ml index 8e74b1bbd..221ea9fdd 100644 --- a/engine/bin/native_driver.ml +++ b/engine/bin/native_driver.ml @@ -1,4 +1,23 @@ open Hax_engine open Base -let _ = Lib.main (Lib.read_options_from_stdin Yojson.Safe.from_string) +let _ = + Hax_io.init + (module struct + let stdin_json_stream = + ref (Yojson.Safe.seq_from_channel In_channel.stdin) + + let read_json () = + match Stdlib.Seq.uncons !stdin_json_stream with + | Some (json, stream) -> + stdin_json_stream := stream; + Some json + | None -> None + + let write_json msg = + let open Stdio.Out_channel in + Yojson.Safe.to_channel stdout msg; + output_char stdout '\n'; + flush stdout + end); + Lib.main () diff --git a/engine/default.nix b/engine/default.nix index 9b8aa609c..1a676c743 100644 --- a/engine/default.nix +++ b/engine/default.nix @@ -46,7 +46,6 @@ src = lib.sourceFilesBySuffices ./. [".ml" ".mli" ".js" "dune" "dune-js" "dune-project" "sh" "rs" "mld"]; buildInputs = with ocamlPackages; [ - zarith_stubs_js base ppx_yojson_conv yojson @@ -54,7 +53,6 @@ ppx_hash pprint non_empty_list - bignum ppx_deriving_yojson ppx_matches ppx_let @@ -64,6 +62,7 @@ ppx_string logs core + stdio re js_of_ocaml ocamlgraph @@ -77,7 +76,6 @@ ppxlib sedlex stdint - zarith ]; nativeBuildInputs = [ rustc diff --git a/engine/dune-project b/engine/dune-project index 6df3f59e8..6cf643031 100644 --- a/engine/dune-project +++ b/engine/dune-project @@ -44,11 +44,9 @@ js_of_ocaml-compiler js_of_ocaml js_of_ocaml-ppx - zarith_stubs_js ; F*-specific dependencies batteries - zarith stdint ppxlib menhirLib diff --git a/engine/hax-engine.opam b/engine/hax-engine.opam index dfa6b8be5..f9ae457ad 100644 --- a/engine/hax-engine.opam +++ b/engine/hax-engine.opam @@ -34,9 +34,7 @@ depends: [ "js_of_ocaml-compiler" "js_of_ocaml" "js_of_ocaml-ppx" - "zarith_stubs_js" "batteries" - "zarith" "stdint" "ppxlib" "menhirLib" diff --git a/engine/lib/ast.ml b/engine/lib/ast.ml index 1fdcb5b93..563b8002f 100644 --- a/engine/lib/ast.ml +++ b/engine/lib/ast.ml @@ -78,9 +78,14 @@ let show_int_kind { size; signedness } = |> Option.map ~f:Int.to_string |> Option.value ~default:"size") -type float_kind = F32 | F64 [@@deriving show, yojson, hash, compare, eq] +type float_kind = F16 | F32 | F64 | F128 +[@@deriving show, yojson, hash, compare, eq] -let show_float_kind = function F32 -> "f32" | F64 -> "f64" +let show_float_kind = function + | F16 -> "f16" + | F32 -> "f32" + | F64 -> "f64" + | F128 -> "f128" type literal = | String of string @@ -126,6 +131,7 @@ functor | TArrow of ty list * ty | TAssociatedType of { impl : impl_expr; item : concrete_ident } | TOpaque of concrete_ident + | TDyn of { witness : F.dyn; goals : dyn_trait_goal list } and generic_value = | GLifetime of { lt : todo; witness : F.lifetime } @@ -151,6 +157,13 @@ functor `SomeTy: Foo`). An `impl_expr` "inhabits" a `trait_goal`. *) + and dyn_trait_goal = { + trait : concrete_ident; + non_self_args : generic_value list; + } + (** A dyn trait: [Foo<_, T0, ..., Tn>]. The generic arguments are known + but the actual type implementing the trait is known only dynamically. *) + and impl_ident = { goal : trait_goal; name : string } (** An impl identifier [{goal; name}] can be: {ul @@ -159,8 +172,22 @@ functor {- An argument that introduces a variable [name] that inhabits [goal].} } *) - (* TODO: ADD SPAN! *) + and projection_predicate = { + impl : impl_expr; + assoc_item : concrete_ident; + typ : ty; + } + (** Expresses a constraints over an associated type. + For instance: + [ + fn f>(...) + ^^^^^^^^^^ + ] + (provided the trait `Foo` has an associated type `S`). + *) + + (* TODO: ADD SPAN! *) and pat' = | PWild | PAscription of { typ : ty; typ_span : span; pat : pat } @@ -195,7 +222,7 @@ functor args : expr list (* ; f_span: span *); generic_args : generic_value list; bounds_impls : impl_expr list; - impl : impl_expr option; + trait : (impl_expr * generic_value list) option; } | Literal of literal | Array of expr list @@ -311,8 +338,16 @@ functor witness : F.nontrivial_lhs; } + (* A guard is a condition on a pattern like: *) + (* match x {.. if guard => .., ..}*) + and guard = { guard : guard'; span : span } + + (* Only if-let guards are supported for now but other variants like regular if *) + (* could be added later (regular if guards are for now desugared as IfLet) *) + and guard' = IfLet of { lhs : pat; rhs : expr; witness : F.match_guard } + (* OCaml + visitors is not happy with `pat`... hence `arm_pat`... *) - and arm' = { arm_pat : pat; body : expr } + and arm' = { arm_pat : pat; body : expr; guard : guard option } and arm = { arm : arm'; span : span } [@@deriving show, yojson, hash, eq] type generic_param = { @@ -330,6 +365,7 @@ functor and generic_constraint = | GCLifetime of todo * F.lifetime | GCType of impl_ident + | GCProjection of projection_predicate (** Trait or lifetime constraints. For instance, `A` and `B` in `fn f()`. *) [@@deriving show, yojson, hash, eq] @@ -407,7 +443,14 @@ functor ii_attrs : attrs; } - and trait_item' = TIType of impl_ident list | TIFn of ty + and trait_item' = + | TIType of impl_ident list + | TIFn of ty + | TIDefault of { + params : param list; + body : expr; + witness : F.trait_item_default; + } and trait_item = { (* TODO: why do I need to prefix by `ti_` here? I guess visitors fail or something *) diff --git a/engine/lib/ast_utils.ml b/engine/lib/ast_utils.ml index 5f688e280..88610da31 100644 --- a/engine/lib/ast_utils.ml +++ b/engine/lib/ast_utils.ml @@ -79,8 +79,9 @@ module Make (F : Features.T) = struct * impl_expr list) option = match e.e with - | App { f; args; generic_args; impl; bounds_impls } -> - Some (f, args, generic_args, impl, bounds_impls) + | App { f; args; generic_args; trait; bounds_impls } -> + (* TODO: propagate full trait *) + Some (f, args, generic_args, Option.map ~f:fst trait, bounds_impls) | _ -> None let pbinding_simple (p : pat) : (local_ident * ty) option = @@ -96,7 +97,7 @@ module Make (F : Features.T) = struct f = { e = GlobalVar (`Concrete f'); _ }; args = [ e ]; generic_args = _; - impl = _; + trait = _; _; (* TODO: see issue #328 *) } @@ -201,7 +202,7 @@ module Make (F : Features.T) = struct f = { e = GlobalVar (`Primitive Deref); _ }; args = [ { e = Borrow { e = sub; _ }; _ } ]; generic_args = _; - impl = _; + trait = _; _; (* TODO: see issue #328 *) } -> @@ -343,7 +344,7 @@ module Make (F : Features.T) = struct f = { e = GlobalVar (`Primitive Cast); _ } as f; args = [ arg ]; generic_args; - impl; + trait; bounds_impls; } -> ascribe @@ -355,7 +356,7 @@ module Make (F : Features.T) = struct f; args = [ ascribe arg ]; generic_args; - impl; + trait; bounds_impls; }; } @@ -377,13 +378,6 @@ module Make (F : Features.T) = struct method! visit_local_ident () x = Set.singleton (module Local_ident) x end - let collect_local_idents = - object - inherit [_] Visitors.reduce as _super - inherit [_] Sets.Local_ident.monoid as _m - method! visit_local_ident () x = Set.singleton (module Local_ident) x - end - include struct open struct type env = Local_ident.t list @@ -416,8 +410,12 @@ module Make (F : Features.T) = struct inherit [_] Visitors.reduce as super inherit [_] Sets.Local_ident.monoid as _m - method! visit_arm' env { arm_pat; body } = - shadows ~env [ arm_pat ] body super#visit_expr + method! visit_arm' env { arm_pat; body; guard } = + match guard with + | None -> shadows ~env [ arm_pat ] body super#visit_expr + | Some { guard = IfLet { lhs; rhs; _ }; _ } -> + shadows ~env [ arm_pat ] rhs super#visit_expr + ++ shadows ~env [ arm_pat; lhs ] body super#visit_expr method! visit_expr' env e = match e with @@ -472,6 +470,8 @@ module Make (F : Features.T) = struct (module Local_ident) end + (* This removes "fake" shadowing introduced by macros. + See PR #368 *) let disambiguate_local_idents (item : item) = let ambiguous = collect_ambiguous_local_idents#visit_item [] item in let local_vars = collect_local_idents#visit_item () item |> ref in @@ -607,8 +607,17 @@ module Make (F : Features.T) = struct (without_vars (self#visit_expr () body) vars)) | _ -> super#visit_expr' () e - method! visit_arm' () { arm_pat; body } = - without_pat_vars (self#visit_expr () body) arm_pat + method! visit_arm' () { arm_pat; body; guard } = + match guard with + | Some { guard = IfLet { lhs; rhs; _ }; _ } -> + let rhs_vars = + without_pat_vars (self#visit_expr () rhs) arm_pat + in + let body_vars = + without_pats_vars (self#visit_expr () body) [ arm_pat; lhs ] + in + Set.union rhs_vars body_vars + | None -> without_pat_vars (self#visit_expr () body) arm_pat end class ['s] expr_list_monoid = @@ -741,6 +750,11 @@ module Make (F : Features.T) = struct if pat_is_expr lhs body then rhs else { body with e = Let { monadic = None; lhs; rhs; body } } + let make_lets (lbs : (pat * expr) list) (body : expr) = + List.fold_right ~init:body + ~f:(fun (pat, expr) body -> make_let pat expr body) + lbs + let make_var_pat (var : local_ident) (typ : ty) (span : span) : pat = { p = PBinding { mut = Immutable; mode = ByValue; var; typ; subpat = None }; @@ -778,6 +792,10 @@ module Make (F : Features.T) = struct let make_wild_pat (typ : ty) (span : span) : pat = { p = PWild; span; typ } + let make_arm (arm_pat : pat) (body : expr) ?(guard : guard option = None) + (span : span) : arm = + { arm = { arm_pat; body; guard }; span } + let make_unit_param (span : span) : param = let typ = unit_typ in let pat = make_wild_pat typ span in @@ -875,7 +893,7 @@ module Make (F : Features.T) = struct args; generic_args = []; bounds_impls = []; - impl; + trait = Option.map ~f:(fun impl -> (impl, [])) impl; }; typ = ret_typ; span; @@ -887,6 +905,13 @@ module Make (F : Features.T) = struct (`Concrete (Concrete_ident.of_name kind f_name)) args span ret_typ + let make_closure (params : pat list) (body : expr) (span : span) : expr = + let params = + match params with [] -> [ make_wild_pat unit_typ span ] | _ -> params + in + let e = Closure { params; body; captures = [] } in + { e; typ = TArrow (List.map ~f:(fun p -> p.typ) params, body.typ); span } + let string_lit span (s : string) : expr = { span; typ = TStr; e = Literal (String s) } @@ -909,6 +934,23 @@ module Make (F : Features.T) = struct let item : AST.item -> Ast.Full.item = Stdlib.Obj.magic end + module Debug : sig + val expr : ?label:string -> AST.expr -> unit + (** Prints an expression pretty-printed as Rust, with its full + AST encoded as JSON, available as a file, so that one can + `jless` or `jq` into it. *) + end = struct + let expr ?(label = "") (e : AST.expr) : unit = + let path = tempfile_path ~suffix:".json" in + Core.Out_channel.write_all path + ~data:([%yojson_of: AST.expr] e |> Yojson.Safe.pretty_to_string); + let e = LiftToFullAst.expr e in + "```rust " ^ label ^ "\n" ^ Print_rust.pexpr_str e + ^ "\n```\x1b[34m JSON-encoded AST available at \x1b[1m" ^ path + ^ "\x1b[0m (hint: use `jless " ^ path ^ "`)" + |> Stdio.prerr_endline + end + let unbox_expr' (next : expr -> expr) (e : expr) : expr = match e.e with | App { f = { e = GlobalVar f; _ }; args = [ e ]; _ } @@ -924,7 +966,7 @@ module Make (F : Features.T) = struct args = [ e ]; generic_args = _; bounds_impls = _; - impl = _; + trait = _; } -> next e | _ -> e @@ -960,7 +1002,7 @@ module Make (F : Features.T) = struct args = [ e ]; generic_args = []; bounds_impls = []; - impl = None (* TODO: see issue #328 *); + trait = None (* TODO: see issue #328 *); }; typ; span; @@ -1060,7 +1102,7 @@ module Make (F : Features.T) = struct args = [ tuple ]; generic_args = [] (* TODO: see issue #328 *); bounds_impls = []; - impl = None (* TODO: see issue #328 *); + trait = None (* TODO: see issue #328 *); }; } @@ -1104,7 +1146,7 @@ module Make (F : Features.T) = struct args = [ place ]; generic_args = _; bounds_impls = _; - impl = _; + trait = _; (* TODO: see issue #328 *) } -> let* place = of_expr place in @@ -1115,7 +1157,7 @@ module Make (F : Features.T) = struct args = [ place; index ]; generic_args = _; bounds_impls = _; - impl = _; + trait = _; (* TODO: see issue #328 *) } when Global_ident.eq_name Core__ops__index__Index__index f -> @@ -1128,7 +1170,7 @@ module Make (F : Features.T) = struct args = [ place; index ]; generic_args = _; bounds_impls = _; - impl = _; + trait = _; (* TODO: see issue #328 *) } when Global_ident.eq_name Core__ops__index__IndexMut__index_mut f -> diff --git a/engine/lib/ast_visitors.ml b/engine/lib/ast_visitors.ml deleted file mode 100644 index 518c0011c..000000000 --- a/engine/lib/ast_visitors.ml +++ /dev/null @@ -1,3147 +0,0 @@ -open Ast -open! Utils -open Base - -module Make = -functor - (F : Features.T) - -> - struct - [@@@warning "-27"] - - open Make (F) - - class virtual ['self] map = - object (self : 'self) - method visit_literal (env : 'env) (this : literal) : literal = - match this with - | String x0 -> - let x0 = self#visit_string env x0 in - String x0 - | Char x0 -> - let x0 = self#visit_char env x0 in - Char x0 - | Int record_payload -> - let value = self#visit_string env record_payload.value in - let negative = self#visit_bool env record_payload.negative in - let kind = self#visit_int_kind env record_payload.kind in - Int { value; negative; kind } - | Float record_payload -> - let value = self#visit_string env record_payload.value in - let negative = self#visit_bool env record_payload.negative in - let kind = self#visit_float_kind env record_payload.kind in - Float { value; negative; kind } - | Bool x0 -> - let x0 = self#visit_bool env x0 in - Bool x0 - - method visit_attr_kind (env : 'env) (this : attr_kind) : attr_kind = - match this with - | Tool record_payload -> - let path = self#visit_string env record_payload.path in - let tokens = self#visit_string env record_payload.tokens in - Tool { path; tokens } - | DocComment record_payload -> - let kind = self#visit_doc_comment_kind env record_payload.kind in - let body = self#visit_string env record_payload.body in - DocComment { kind; body } - - method visit_attr (env : 'env) (this : attr) : attr = - let kind = self#visit_attr_kind env this.kind in - let span = self#visit_span env this.span in - let out : attr = { kind; span } in - out - - method visit_doc_comment_kind (env : 'env) (this : doc_comment_kind) - : doc_comment_kind = - match this with DCKLine -> DCKLine | DCKBlock -> DCKBlock - - method visit_borrow_kind (env : 'env) (this : borrow_kind) : borrow_kind - = - match this with - | Shared -> Shared - | Unique -> Unique - | Mut x0 -> - let x0 = self#visit_feature_mutable_reference env x0 in - Mut x0 - - method visit_binding_mode (env : 'env) (this : binding_mode) - : binding_mode = - match this with - | ByValue -> ByValue - | ByRef (x0, x1) -> - let x0 = self#visit_borrow_kind env x0 in - let x1 = self#visit_feature_reference env x1 in - ByRef (x0, x1) - - method visit_ty (env : 'env) (this : ty) : ty = - match this with - | TBool -> TBool - | TChar -> TChar - | TInt x0 -> - let x0 = self#visit_int_kind env x0 in - TInt x0 - | TFloat x0 -> - let x0 = self#visit_float_kind env x0 in - TFloat x0 - | TStr -> TStr - | TApp record_payload -> - let ident = self#visit_global_ident env record_payload.ident in - let args = - self#visit_list self#visit_generic_value env record_payload.args - in - TApp { ident; args } - | TArray record_payload -> - let typ = self#visit_ty env record_payload.typ in - let length = self#visit_expr env record_payload.length in - TArray { typ; length } - | TSlice record_payload -> - let witness = - self#visit_feature_slice env record_payload.witness - in - let ty = self#visit_ty env record_payload.ty in - TSlice { witness; ty } - | TRawPointer record_payload -> - let witness = - self#visit_feature_raw_pointer env record_payload.witness - in - TRawPointer { witness } - | TRef record_payload -> - let witness = - self#visit_feature_reference env record_payload.witness - in - let region = self#visit_todo env record_payload.region in - let typ = self#visit_ty env record_payload.typ in - let mut = - self#visit_mutability self#visit_feature_mutable_reference env - record_payload.mut - in - TRef { witness; region; typ; mut } - | TParam x0 -> - let x0 = self#visit_local_ident env x0 in - TParam x0 - | TArrow (x0, x1) -> - let x0 = self#visit_list self#visit_ty env x0 in - let x1 = self#visit_ty env x1 in - TArrow (x0, x1) - | TAssociatedType record_payload -> - let impl = self#visit_impl_expr env record_payload.impl in - let item = self#visit_concrete_ident env record_payload.item in - TAssociatedType { impl; item } - | TOpaque x0 -> - let x0 = self#visit_concrete_ident env x0 in - TOpaque x0 - - method visit_generic_value (env : 'env) (this : generic_value) - : generic_value = - match this with - | GLifetime record_payload -> - let lt = self#visit_todo env record_payload.lt in - let witness = - self#visit_feature_lifetime env record_payload.witness - in - GLifetime { lt; witness } - | GType x0 -> - let x0 = self#visit_ty env x0 in - GType x0 - | GConst x0 -> - let x0 = self#visit_expr env x0 in - GConst x0 - - method visit_impl_expr (env : 'env) (this : impl_expr) : impl_expr = - match this with - | Self -> Self - | Concrete x0 -> - let x0 = self#visit_trait_goal env x0 in - Concrete x0 - | LocalBound record_payload -> - let id = self#visit_string env record_payload.id in - LocalBound { id } - | Parent record_payload -> - let impl = self#visit_impl_expr env record_payload.impl in - let ident = self#visit_impl_ident env record_payload.ident in - Parent { impl; ident } - | Projection record_payload -> - let impl = self#visit_impl_expr env record_payload.impl in - let ident = self#visit_impl_ident env record_payload.ident in - let item = self#visit_concrete_ident env record_payload.item in - Projection { impl; ident; item } - | ImplApp record_payload -> - let impl = self#visit_impl_expr env record_payload.impl in - let args = - self#visit_list self#visit_impl_expr env record_payload.args - in - ImplApp { impl; args } - | Dyn -> Dyn - | Builtin x0 -> - let x0 = self#visit_trait_goal env x0 in - Builtin x0 - - method visit_trait_goal (env : 'env) (this : trait_goal) : trait_goal = - let trait = self#visit_concrete_ident env this.trait in - let args = self#visit_list self#visit_generic_value env this.args in - let out : trait_goal = { trait; args } in - out - - method visit_impl_ident (env : 'env) (this : impl_ident) : impl_ident = - let goal = self#visit_trait_goal env this.goal in - let out : impl_ident = { goal; name = this.name } in - out - - method visit_pat' (env : 'env) (this : pat') : pat' = - match this with - | PWild -> PWild - | PAscription record_payload -> - let typ = self#visit_ty env record_payload.typ in - let typ_span = self#visit_span env record_payload.typ_span in - let pat = self#visit_pat env record_payload.pat in - PAscription { typ; typ_span; pat } - | PConstruct record_payload -> - let name = self#visit_global_ident env record_payload.name in - let args = - self#visit_list self#visit_field_pat env record_payload.args - in - let is_record = self#visit_bool env record_payload.is_record in - let is_struct = self#visit_bool env record_payload.is_struct in - PConstruct { name; args; is_record; is_struct } - | POr record_payload -> - let subpats = - self#visit_list self#visit_pat env record_payload.subpats - in - POr { subpats } - | PArray record_payload -> - let args = - self#visit_list self#visit_pat env record_payload.args - in - PArray { args } - | PDeref record_payload -> - let subpat = self#visit_pat env record_payload.subpat in - let witness = - self#visit_feature_reference env record_payload.witness - in - PDeref { subpat; witness } - | PConstant record_payload -> - let lit = self#visit_literal env record_payload.lit in - PConstant { lit } - | PBinding record_payload -> - let mut = - self#visit_mutability self#visit_feature_mutable_variable env - record_payload.mut - in - let mode = self#visit_binding_mode env record_payload.mode in - let var = self#visit_local_ident env record_payload.var in - let typ = self#visit_ty env record_payload.typ in - let subpat = - self#visit_option - (self#visit_tuple2 self#visit_pat - self#visit_feature_as_pattern) - env record_payload.subpat - in - PBinding { mut; mode; var; typ; subpat } - - method visit_pat (env : 'env) (this : pat) : pat = - let p = self#visit_pat' env this.p in - let span = self#visit_span env this.span in - let typ = self#visit_ty env this.typ in - let out : pat = { p; span; typ } in - out - - method visit_field_pat (env : 'env) (this : field_pat) : field_pat = - let field = self#visit_global_ident env this.field in - let pat = self#visit_pat env this.pat in - let out : field_pat = { field; pat } in - out - - method visit_expr' (env : 'env) (this : expr') : expr' = - match this with - | If record_payload -> - let cond = self#visit_expr env record_payload.cond in - let then_ = self#visit_expr env record_payload.then_ in - let else_ = - self#visit_option self#visit_expr env record_payload.else_ - in - If { cond; then_; else_ } - | App record_payload -> - let f = self#visit_expr env record_payload.f in - let args = - self#visit_list self#visit_expr env record_payload.args - in - let generic_args = - self#visit_list self#visit_generic_value env - record_payload.generic_args - in - let bounds_impls = - self#visit_list self#visit_impl_expr env - record_payload.bounds_impls - in - let impl = - self#visit_option self#visit_impl_expr env record_payload.impl - in - App { f; args; generic_args; impl; bounds_impls } - | Literal x0 -> - let x0 = self#visit_literal env x0 in - Literal x0 - | Array x0 -> - let x0 = self#visit_list self#visit_expr env x0 in - Array x0 - | Construct record_payload -> - let constructor = - self#visit_global_ident env record_payload.constructor - in - let is_record = self#visit_bool env record_payload.is_record in - let is_struct = self#visit_bool env record_payload.is_struct in - let fields = - self#visit_list - (self#visit_tuple2 self#visit_global_ident self#visit_expr) - env record_payload.fields - in - let base = - self#visit_option - (self#visit_tuple2 self#visit_expr - self#visit_feature_construct_base) - env record_payload.base - in - Construct { constructor; is_record; is_struct; fields; base } - | Match record_payload -> - let scrutinee = self#visit_expr env record_payload.scrutinee in - let arms = - self#visit_list self#visit_arm env record_payload.arms - in - Match { scrutinee; arms } - | Let record_payload -> - let monadic = - self#visit_option - (self#visit_tuple2 self#visit_supported_monads - self#visit_feature_monadic_binding) - env record_payload.monadic - in - let lhs = self#visit_pat env record_payload.lhs in - let rhs = self#visit_expr env record_payload.rhs in - let body = self#visit_expr env record_payload.body in - Let { monadic; lhs; rhs; body } - | Block (x0, x1) -> - let x0 = self#visit_expr env x0 in - let x1 = self#visit_feature_block env x1 in - Block (x0, x1) - | LocalVar x0 -> - let x0 = self#visit_local_ident env x0 in - LocalVar x0 - | GlobalVar x0 -> - let x0 = self#visit_global_ident env x0 in - GlobalVar x0 - | Ascription record_payload -> - let e = self#visit_expr env record_payload.e in - let typ = self#visit_ty env record_payload.typ in - Ascription { e; typ } - | MacroInvokation record_payload -> - let macro = self#visit_global_ident env record_payload.macro in - let args = self#visit_string env record_payload.args in - let witness = - self#visit_feature_macro env record_payload.witness - in - MacroInvokation { macro; args; witness } - | Assign record_payload -> - let lhs = self#visit_lhs env record_payload.lhs in - let e = self#visit_expr env record_payload.e in - let witness = - self#visit_feature_mutable_variable env record_payload.witness - in - Assign { lhs; e; witness } - | Loop record_payload -> - let body = self#visit_expr env record_payload.body in - let kind = self#visit_loop_kind env record_payload.kind in - let state = - self#visit_option self#visit_loop_state env record_payload.state - in - let label = - self#visit_option self#visit_string env record_payload.label - in - let witness = - self#visit_feature_loop env record_payload.witness - in - Loop { body; kind; state; label; witness } - | Break record_payload -> - let e = self#visit_expr env record_payload.e in - let label = - self#visit_option self#visit_string env record_payload.label - in - let witness = - self#visit_tuple2 self#visit_feature_break - self#visit_feature_loop env record_payload.witness - in - Break { e; label; witness } - | Return record_payload -> - let e = self#visit_expr env record_payload.e in - let witness = - self#visit_feature_early_exit env record_payload.witness - in - Return { e; witness } - | QuestionMark record_payload -> - let e = self#visit_expr env record_payload.e in - let return_typ = self#visit_ty env record_payload.return_typ in - let witness = - self#visit_feature_question_mark env record_payload.witness - in - QuestionMark { e; return_typ; witness } - | Continue record_payload -> - let e = - self#visit_option - (self#visit_tuple2 self#visit_feature_state_passing_loop - self#visit_expr) - env record_payload.e - in - let label = - self#visit_option self#visit_string env record_payload.label - in - let witness = - self#visit_tuple2 self#visit_feature_continue - self#visit_feature_loop env record_payload.witness - in - Continue { e; label; witness } - | Borrow record_payload -> - let kind = self#visit_borrow_kind env record_payload.kind in - let e = self#visit_expr env record_payload.e in - let witness = - self#visit_feature_reference env record_payload.witness - in - Borrow { kind; e; witness } - | AddressOf record_payload -> - let mut = - self#visit_mutability self#visit_feature_mutable_pointer env - record_payload.mut - in - let e = self#visit_expr env record_payload.e in - let witness = - self#visit_feature_raw_pointer env record_payload.witness - in - AddressOf { mut; e; witness } - | Closure record_payload -> - let params = - self#visit_list self#visit_pat env record_payload.params - in - let body = self#visit_expr env record_payload.body in - let captures = - self#visit_list self#visit_expr env record_payload.captures - in - Closure { params; body; captures } - | EffectAction record_payload -> - let action = - self#visit_feature_monadic_action env record_payload.action - in - let argument = self#visit_expr env record_payload.argument in - EffectAction { action; argument } - | Quote quote -> Quote (self#visit_quote env quote) - - method visit_expr (env : 'env) (this : expr) : expr = - let e = self#visit_expr' env this.e in - let span = self#visit_span env this.span in - let typ = self#visit_ty env this.typ in - let out : expr = { e; span; typ } in - out - - method visit_quote (env : 'env) ({ contents; witness } : quote) : quote - = - let contents = - self#visit_list - (fun env -> function - | `Verbatim code -> `Verbatim code - | `Expr e -> `Expr (self#visit_expr env e) - | `Pat p -> `Pat (self#visit_pat env p) - | `Typ t -> `Typ (self#visit_ty env t)) - env contents - in - let witness = self#visit_feature_quote env witness in - { contents; witness } - - method visit_supported_monads (env : 'env) (this : supported_monads) - : supported_monads = - match this with - | MException x0 -> - let x0 = self#visit_ty env x0 in - MException x0 - | MResult x0 -> - let x0 = self#visit_ty env x0 in - MResult x0 - | MOption -> MOption - - method visit_loop_kind (env : 'env) (this : loop_kind) : loop_kind = - match this with - | UnconditionalLoop -> UnconditionalLoop - | WhileLoop record_payload -> - let condition = self#visit_expr env record_payload.condition in - let witness = - self#visit_feature_while_loop env record_payload.witness - in - WhileLoop { condition; witness } - | ForLoop record_payload -> - let pat = self#visit_pat env record_payload.pat in - let it = self#visit_expr env record_payload.it in - let witness = - self#visit_feature_for_loop env record_payload.witness - in - ForLoop { pat; it; witness } - | ForIndexLoop record_payload -> - let start = self#visit_expr env record_payload.start in - let end_ = self#visit_expr env record_payload.end_ in - let var = self#visit_local_ident env record_payload.var in - let var_typ = self#visit_ty env record_payload.var_typ in - let witness = - self#visit_feature_for_index_loop env record_payload.witness - in - ForIndexLoop { start; end_; var; var_typ; witness } - - method visit_loop_state (env : 'env) (this : loop_state) : loop_state = - let init = self#visit_expr env this.init in - let bpat = self#visit_pat env this.bpat in - let witness = - self#visit_feature_state_passing_loop env this.witness - in - let out : loop_state = { init; bpat; witness } in - out - - method visit_lhs (env : 'env) (this : lhs) : lhs = - match this with - | LhsLocalVar record_payload -> - let var = self#visit_local_ident env record_payload.var in - let typ = self#visit_ty env record_payload.typ in - LhsLocalVar { var; typ } - | LhsArbitraryExpr record_payload -> - let e = self#visit_expr env record_payload.e in - let witness = - self#visit_feature_arbitrary_lhs env record_payload.witness - in - LhsArbitraryExpr { e; witness } - | LhsFieldAccessor record_payload -> - let e = self#visit_lhs env record_payload.e in - let typ = self#visit_ty env record_payload.typ in - let field = self#visit_global_ident env record_payload.field in - let witness = - self#visit_feature_nontrivial_lhs env record_payload.witness - in - LhsFieldAccessor { e; typ; field; witness } - | LhsArrayAccessor record_payload -> - let e = self#visit_lhs env record_payload.e in - let typ = self#visit_ty env record_payload.typ in - let index = self#visit_expr env record_payload.index in - let witness = - self#visit_feature_nontrivial_lhs env record_payload.witness - in - LhsArrayAccessor { e; typ; index; witness } - - method visit_arm' (env : 'env) (this : arm') : arm' = - let arm_pat = self#visit_pat env this.arm_pat in - let body = self#visit_expr env this.body in - let out : arm' = { arm_pat; body } in - out - - method visit_arm (env : 'env) (this : arm) : arm = - let arm = self#visit_arm' env this.arm in - let span = self#visit_span env this.span in - let out : arm = { arm; span } in - out - - method visit_generic_param (env : 'env) (this : generic_param) - : generic_param = - let ident = self#visit_local_ident env this.ident in - let span = self#visit_span env this.span in - let attrs = self#visit_list self#visit_attr env this.attrs in - let kind = self#visit_generic_param_kind env this.kind in - let out : generic_param = { ident; span; attrs; kind } in - out - - method visit_generic_param_kind (env : 'env) (this : generic_param_kind) - : generic_param_kind = - match this with - | GPLifetime record_payload -> - let witness = - self#visit_feature_lifetime env record_payload.witness - in - GPLifetime { witness } - | GPType record_payload -> - let default = - self#visit_option self#visit_ty env record_payload.default - in - GPType { default } - | GPConst record_payload -> - let typ = self#visit_ty env record_payload.typ in - GPConst { typ } - - method visit_generic_constraint (env : 'env) (this : generic_constraint) - : generic_constraint = - match this with - | GCLifetime (x0, x1) -> - let x0 = self#visit_todo env x0 in - let x1 = self#visit_feature_lifetime env x1 in - GCLifetime (x0, x1) - | GCType x0 -> - let x0 = self#visit_impl_ident env x0 in - GCType x0 - - method visit_param (env : 'env) (this : param) : param = - let pat = self#visit_pat env this.pat in - let typ = self#visit_ty env this.typ in - let typ_span = self#visit_option self#visit_span env this.typ_span in - let attrs = self#visit_list self#visit_attr env this.attrs in - let out : param = { pat; typ; typ_span; attrs } in - out - - method visit_generics (env : 'env) (this : generics) : generics = - let params = - self#visit_list self#visit_generic_param env this.params - in - let constraints = - self#visit_list self#visit_generic_constraint env this.constraints - in - let out : generics = { params; constraints } in - out - - method visit_variant (env : 'env) (this : variant) : variant = - let name = self#visit_concrete_ident env this.name in - let arguments = - self#visit_list - (self#visit_tuple3 self#visit_concrete_ident self#visit_ty - (self#visit_list self#visit_attr)) - env this.arguments - in - let is_record = self#visit_bool env this.is_record in - let attrs = self#visit_list self#visit_attr env this.attrs in - let out : variant = { name; arguments; is_record; attrs } in - out - - method visit_item' (env : 'env) (this : item') : item' = - match this with - | Fn record_payload -> - let name = self#visit_concrete_ident env record_payload.name in - let generics = self#visit_generics env record_payload.generics in - let body = self#visit_expr env record_payload.body in - let params = - self#visit_list self#visit_param env record_payload.params - in - Fn { name; generics; body; params } - | TyAlias record_payload -> - let name = self#visit_concrete_ident env record_payload.name in - let generics = self#visit_generics env record_payload.generics in - let ty = self#visit_ty env record_payload.ty in - TyAlias { name; generics; ty } - | Type record_payload -> - let name = self#visit_concrete_ident env record_payload.name in - let generics = self#visit_generics env record_payload.generics in - let variants = - self#visit_list self#visit_variant env record_payload.variants - in - let is_struct = self#visit_bool env record_payload.is_struct in - Type { name; generics; variants; is_struct } - | IMacroInvokation record_payload -> - let macro = self#visit_concrete_ident env record_payload.macro in - let argument = self#visit_string env record_payload.argument in - let span = self#visit_span env record_payload.span in - let witness = - self#visit_feature_macro env record_payload.witness - in - IMacroInvokation { macro; argument; span; witness } - | Trait record_payload -> - let name = self#visit_concrete_ident env record_payload.name in - let generics = self#visit_generics env record_payload.generics in - let items = - self#visit_list self#visit_trait_item env record_payload.items - in - Trait { name; generics; items } - | Impl record_payload -> - let generics = self#visit_generics env record_payload.generics in - let self_ty = self#visit_ty env record_payload.self_ty in - let of_trait = - self#visit_tuple2 self#visit_global_ident - (self#visit_list self#visit_generic_value) - env record_payload.of_trait - in - let items = - self#visit_list self#visit_impl_item env record_payload.items - in - let parent_bounds = - self#visit_list - (self#visit_tuple2 self#visit_impl_expr self#visit_impl_ident) - env record_payload.parent_bounds - in - Impl { generics; self_ty; of_trait; items; parent_bounds } - | Alias record_payload -> - let name = self#visit_concrete_ident env record_payload.name in - let item = self#visit_concrete_ident env record_payload.item in - Alias { name; item } - | Use record_payload -> - let path = - self#visit_list self#visit_string env record_payload.path - in - let is_external = - self#visit_bool env record_payload.is_external - in - let rename = - self#visit_option self#visit_string env record_payload.rename - in - Use { path; is_external; rename } - | Quote quote -> Quote (self#visit_quote env quote) - | HaxError x0 -> - let x0 = self#visit_string env x0 in - HaxError x0 - | NotImplementedYet -> NotImplementedYet - - method visit_item (env : 'env) (this : item) : item = - let v = self#visit_item' env this.v in - let span = self#visit_span env this.span in - let ident = self#visit_concrete_ident env this.ident in - let attrs = self#visit_list self#visit_attr env this.attrs in - let out : item = { v; span; ident; attrs } in - out - - method visit_impl_item' (env : 'env) (this : impl_item') : impl_item' = - match this with - | IIType record_payload -> - let typ = self#visit_ty env record_payload.typ in - let parent_bounds = - self#visit_list - (self#visit_tuple2 self#visit_impl_expr self#visit_impl_ident) - env record_payload.parent_bounds - in - IIType { typ; parent_bounds } - | IIFn record_payload -> - let body = self#visit_expr env record_payload.body in - let params = - self#visit_list self#visit_param env record_payload.params - in - IIFn { body; params } - - method visit_impl_item (env : 'env) (this : impl_item) : impl_item = - let ii_span = self#visit_span env this.ii_span in - let ii_generics = self#visit_generics env this.ii_generics in - let ii_v = self#visit_impl_item' env this.ii_v in - let ii_ident = self#visit_concrete_ident env this.ii_ident in - let ii_attrs = self#visit_list self#visit_attr env this.ii_attrs in - let out : impl_item = - { ii_span; ii_generics; ii_v; ii_ident; ii_attrs } - in - out - - method visit_trait_item' (env : 'env) (this : trait_item') : trait_item' - = - match this with - | TIType x0 -> - let x0 = self#visit_list self#visit_impl_ident env x0 in - TIType x0 - | TIFn x0 -> - let x0 = self#visit_ty env x0 in - TIFn x0 - - method visit_trait_item (env : 'env) (this : trait_item) : trait_item = - let ti_span = self#visit_span env this.ti_span in - let ti_generics = self#visit_generics env this.ti_generics in - let ti_v = self#visit_trait_item' env this.ti_v in - let ti_ident = self#visit_concrete_ident env this.ti_ident in - let ti_attrs = self#visit_list self#visit_attr env this.ti_attrs in - let out : trait_item = - { ti_span; ti_generics; ti_v; ti_ident; ti_attrs } - in - out - - method visit_list : 'a. ('env -> 'a -> 'a) -> 'env -> 'a list -> 'a list - = - fun v env -> Base.List.map ~f:(v env) - - method visit_option - : 'a. ('env -> 'a -> 'a) -> 'env -> 'a option -> 'a option = - fun v env this -> - match this with None -> None | Some x -> Some (v env x) - - method visit_tuple2 - : 'a 'b. - ('env -> 'a -> 'a) -> - ('env -> 'b -> 'b) -> - 'env -> - 'a * 'b -> - 'a * 'b = - fun vx vy env (x, y) -> - let x = vx env x in - let y = vy env y in - (x, y) - - method visit_tuple3 - : 'a 'b 'c. - ('env -> 'a -> 'a) -> - ('env -> 'b -> 'b) -> - ('env -> 'c -> 'c) -> - 'env -> - 'a * 'b * 'c -> - 'a * 'b * 'c = - fun vx vy vz env (x, y, z) -> - let x = vx env x in - let y = vy env y in - let z = vz env z in - (x, y, z) - - method visit_mutability - : 'a. ('env -> 'a -> 'a) -> 'env -> 'a mutability -> 'a mutability = - fun v env this -> this - - method visit_todo : 'env -> todo -> todo = fun _ x -> x - method visit_string : 'env -> string -> string = fun _ x -> x - method visit_span : 'env -> span -> span = fun _ x -> x - - method visit_local_ident : 'env -> local_ident -> local_ident = - fun _ x -> x - - method visit_global_ident : 'env -> global_ident -> global_ident = - fun _ x -> x - - method visit_concrete_ident : 'env -> concrete_ident -> concrete_ident = - fun _ x -> x - - method visit_char : 'env -> char -> char = fun _ x -> x - method visit_bool : 'env -> bool -> bool = fun _ x -> x - method visit_int_kind : 'env -> int_kind -> int_kind = fun _ x -> x - - method visit_float_kind : 'env -> float_kind -> float_kind = - fun _ x -> x - - method visit_feature_mutable_reference - : 'env -> F.mutable_reference -> F.mutable_reference = - fun _ x -> x - - method visit_feature_reference : 'env -> F.reference -> F.reference = - fun _ x -> x - - method visit_feature_slice : 'env -> F.slice -> F.slice = fun _ x -> x - - method visit_feature_raw_pointer - : 'env -> F.raw_pointer -> F.raw_pointer = - fun _ x -> x - - method visit_feature_lifetime : 'env -> F.lifetime -> F.lifetime = - fun _ x -> x - - method visit_feature_mutable_variable - : 'env -> F.mutable_variable -> F.mutable_variable = - fun _ x -> x - - method visit_feature_as_pattern : 'env -> F.as_pattern -> F.as_pattern = - fun _ x -> x - - method visit_feature_construct_base - : 'env -> F.construct_base -> F.construct_base = - fun _ x -> x - - method visit_feature_monadic_binding - : 'env -> F.monadic_binding -> F.monadic_binding = - fun _ x -> x - - method visit_feature_block : 'env -> F.block -> F.block = fun _ x -> x - method visit_feature_macro : 'env -> F.macro -> F.macro = fun _ x -> x - method visit_feature_loop : 'env -> F.loop -> F.loop = fun _ x -> x - method visit_feature_break : 'env -> F.break -> F.break = fun _ x -> x - - method visit_feature_early_exit : 'env -> F.early_exit -> F.early_exit = - fun _ x -> x - - method visit_feature_question_mark - : 'env -> F.question_mark -> F.question_mark = - fun _ x -> x - - method visit_feature_state_passing_loop - : 'env -> F.state_passing_loop -> F.state_passing_loop = - fun _ x -> x - - method visit_feature_continue : 'env -> F.continue -> F.continue = - fun _ x -> x - - method visit_feature_mutable_pointer - : 'env -> F.mutable_pointer -> F.mutable_pointer = - fun _ x -> x - - method visit_feature_monadic_action - : 'env -> F.monadic_action -> F.monadic_action = - fun _ x -> x - - method visit_feature_while_loop : 'env -> F.while_loop -> F.while_loop = - fun _ x -> x - - method visit_feature_for_loop : 'env -> F.for_loop -> F.for_loop = - fun _ x -> x - - method visit_feature_for_index_loop - : 'env -> F.for_index_loop -> F.for_index_loop = - fun _ x -> x - - method visit_feature_arbitrary_lhs - : 'env -> F.arbitrary_lhs -> F.arbitrary_lhs = - fun _ x -> x - - method visit_feature_nontrivial_lhs - : 'env -> F.nontrivial_lhs -> F.nontrivial_lhs = - fun _ x -> x - - method visit_feature_quote : 'env -> F.quote -> F.quote = fun _ x -> x - end - - class virtual ['self] mapreduce = - object (self : 'self) - method visit_literal (env : 'env) (this : literal) : literal * 'acc = - match this with - | String x0 -> - let x0, reduce_acc = self#visit_string env x0 in - (String x0, reduce_acc) - | Char x0 -> - let x0, reduce_acc = self#visit_char env x0 in - (Char x0, reduce_acc) - | Int record_payload -> - let value, reduce_acc = - self#visit_string env record_payload.value - in - let negative, reduce_acc' = - self#visit_bool env record_payload.negative - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let kind, reduce_acc' = - self#visit_int_kind env record_payload.kind - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (Int { value; negative; kind }, reduce_acc) - | Float record_payload -> - let value, reduce_acc = - self#visit_string env record_payload.value - in - let negative, reduce_acc' = - self#visit_bool env record_payload.negative - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let kind, reduce_acc' = - self#visit_float_kind env record_payload.kind - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (Float { value; negative; kind }, reduce_acc) - | Bool x0 -> - let x0, reduce_acc = self#visit_bool env x0 in - (Bool x0, reduce_acc) - - method visit_attr_kind (env : 'env) (this : attr_kind) - : attr_kind * 'acc = - match this with - | Tool record_payload -> - let path, reduce_acc = - self#visit_string env record_payload.path - in - let tokens, reduce_acc' = - self#visit_string env record_payload.tokens - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (Tool { path; tokens }, reduce_acc) - | DocComment record_payload -> - let kind, reduce_acc = - self#visit_doc_comment_kind env record_payload.kind - in - let body, reduce_acc' = - self#visit_string env record_payload.body - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (DocComment { kind; body }, reduce_acc) - - method visit_attr (env : 'env) (this : attr) : attr * 'acc = - let kind, reduce_acc = self#visit_attr_kind env this.kind in - let span, reduce_acc' = self#visit_span env this.span in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let out : attr = { kind; span } in - (out, reduce_acc) - - method visit_doc_comment_kind (env : 'env) (this : doc_comment_kind) - : doc_comment_kind * 'acc = - match this with - | DCKLine -> (DCKLine, self#zero) - | DCKBlock -> (DCKBlock, self#zero) - - method visit_borrow_kind (env : 'env) (this : borrow_kind) - : borrow_kind * 'acc = - match this with - | Shared -> (Shared, self#zero) - | Unique -> (Unique, self#zero) - | Mut x0 -> - let x0, reduce_acc = - self#visit_feature_mutable_reference env x0 - in - (Mut x0, reduce_acc) - - method visit_binding_mode (env : 'env) (this : binding_mode) - : binding_mode * 'acc = - match this with - | ByValue -> (ByValue, self#zero) - | ByRef (x0, x1) -> - let x0, reduce_acc = self#visit_borrow_kind env x0 in - let x1, reduce_acc' = self#visit_feature_reference env x1 in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (ByRef (x0, x1), reduce_acc) - - method visit_ty (env : 'env) (this : ty) : ty * 'acc = - match this with - | TBool -> (TBool, self#zero) - | TChar -> (TChar, self#zero) - | TInt x0 -> - let x0, reduce_acc = self#visit_int_kind env x0 in - (TInt x0, reduce_acc) - | TFloat x0 -> - let x0, reduce_acc = self#visit_float_kind env x0 in - (TFloat x0, reduce_acc) - | TStr -> (TStr, self#zero) - | TApp record_payload -> - let ident, reduce_acc = - self#visit_global_ident env record_payload.ident - in - let args, reduce_acc' = - self#visit_list self#visit_generic_value env record_payload.args - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (TApp { ident; args }, reduce_acc) - | TArray record_payload -> - let typ, reduce_acc = self#visit_ty env record_payload.typ in - let length, reduce_acc' = - self#visit_expr env record_payload.length - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (TArray { typ; length }, reduce_acc) - | TSlice record_payload -> - let witness, reduce_acc = - self#visit_feature_slice env record_payload.witness - in - let ty, reduce_acc' = self#visit_ty env record_payload.ty in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (TSlice { witness; ty }, reduce_acc) - | TRawPointer record_payload -> - let witness, reduce_acc = - self#visit_feature_raw_pointer env record_payload.witness - in - (TRawPointer { witness }, reduce_acc) - | TRef record_payload -> - let witness, reduce_acc = - self#visit_feature_reference env record_payload.witness - in - let region, reduce_acc' = - self#visit_todo env record_payload.region - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let typ, reduce_acc' = self#visit_ty env record_payload.typ in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let mut, reduce_acc' = - self#visit_mutability self#visit_feature_mutable_reference env - record_payload.mut - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (TRef { witness; region; typ; mut }, reduce_acc) - | TParam x0 -> - let x0, reduce_acc = self#visit_local_ident env x0 in - (TParam x0, reduce_acc) - | TArrow (x0, x1) -> - let x0, reduce_acc = self#visit_list self#visit_ty env x0 in - let x1, reduce_acc' = self#visit_ty env x1 in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (TArrow (x0, x1), reduce_acc) - | TAssociatedType record_payload -> - let impl, reduce_acc = - self#visit_impl_expr env record_payload.impl - in - let item, reduce_acc' = - self#visit_concrete_ident env record_payload.item - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (TAssociatedType { impl; item }, reduce_acc) - | TOpaque x0 -> - let x0, reduce_acc = self#visit_concrete_ident env x0 in - (TOpaque x0, reduce_acc) - - method visit_generic_value (env : 'env) (this : generic_value) - : generic_value * 'acc = - match this with - | GLifetime record_payload -> - let lt, reduce_acc = self#visit_todo env record_payload.lt in - let witness, reduce_acc' = - self#visit_feature_lifetime env record_payload.witness - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (GLifetime { lt; witness }, reduce_acc) - | GType x0 -> - let x0, reduce_acc = self#visit_ty env x0 in - (GType x0, reduce_acc) - | GConst x0 -> - let x0, reduce_acc = self#visit_expr env x0 in - (GConst x0, reduce_acc) - - method visit_impl_expr (env : 'env) (this : impl_expr) - : impl_expr * 'acc = - match this with - | Self -> (Self, self#zero) - | Concrete x0 -> - let x0, reduce_acc = self#visit_trait_goal env x0 in - (Concrete x0, reduce_acc) - | LocalBound record_payload -> - let id, reduce_acc = self#visit_string env record_payload.id in - (LocalBound { id }, reduce_acc) - | Parent record_payload -> - let impl, reduce_acc = - self#visit_impl_expr env record_payload.impl - in - let ident, reduce_acc' = - self#visit_impl_ident env record_payload.ident - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (Parent { impl; ident }, reduce_acc) - | Projection record_payload -> - let impl, reduce_acc = - self#visit_impl_expr env record_payload.impl - in - let ident, reduce_acc' = - self#visit_impl_ident env record_payload.ident - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let item, reduce_acc' = - self#visit_concrete_ident env record_payload.item - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (Projection { impl; ident; item }, reduce_acc) - | ImplApp record_payload -> - let impl, reduce_acc = - self#visit_impl_expr env record_payload.impl - in - let args, reduce_acc' = - self#visit_list self#visit_impl_expr env record_payload.args - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (ImplApp { impl; args }, reduce_acc) - | Dyn -> (Dyn, self#zero) - | Builtin x0 -> - let x0, reduce_acc = self#visit_trait_goal env x0 in - (Builtin x0, reduce_acc) - - method visit_trait_goal (env : 'env) (this : trait_goal) - : trait_goal * 'acc = - let trait, reduce_acc = self#visit_concrete_ident env this.trait in - let args, reduce_acc' = - self#visit_list self#visit_generic_value env this.args - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let out : trait_goal = { trait; args } in - (out, reduce_acc) - - method visit_impl_ident (env : 'env) (this : impl_ident) - : impl_ident * 'acc = - let goal, reduce_acc = self#visit_trait_goal env this.goal in - let out : impl_ident = { goal; name = this.name } in - (out, reduce_acc) - - method visit_pat' (env : 'env) (this : pat') : pat' * 'acc = - match this with - | PWild -> (PWild, self#zero) - | PAscription record_payload -> - let typ, reduce_acc = self#visit_ty env record_payload.typ in - let typ_span, reduce_acc' = - self#visit_span env record_payload.typ_span - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let pat, reduce_acc' = self#visit_pat env record_payload.pat in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (PAscription { typ; typ_span; pat }, reduce_acc) - | PConstruct record_payload -> - let name, reduce_acc = - self#visit_global_ident env record_payload.name - in - let args, reduce_acc' = - self#visit_list self#visit_field_pat env record_payload.args - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let is_record, reduce_acc' = - self#visit_bool env record_payload.is_record - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let is_struct, reduce_acc' = - self#visit_bool env record_payload.is_struct - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (PConstruct { name; args; is_record; is_struct }, reduce_acc) - | POr record_payload -> - let subpats, reduce_acc = - self#visit_list self#visit_pat env record_payload.subpats - in - (POr { subpats }, reduce_acc) - | PArray record_payload -> - let args, reduce_acc = - self#visit_list self#visit_pat env record_payload.args - in - (PArray { args }, reduce_acc) - | PDeref record_payload -> - let subpat, reduce_acc = - self#visit_pat env record_payload.subpat - in - let witness, reduce_acc' = - self#visit_feature_reference env record_payload.witness - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (PDeref { subpat; witness }, reduce_acc) - | PConstant record_payload -> - let lit, reduce_acc = self#visit_literal env record_payload.lit in - (PConstant { lit }, reduce_acc) - | PBinding record_payload -> - let mut, reduce_acc = - self#visit_mutability self#visit_feature_mutable_variable env - record_payload.mut - in - let mode, reduce_acc' = - self#visit_binding_mode env record_payload.mode - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let var, reduce_acc' = - self#visit_local_ident env record_payload.var - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let typ, reduce_acc' = self#visit_ty env record_payload.typ in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let subpat, reduce_acc' = - self#visit_option - (self#visit_tuple2 self#visit_pat - self#visit_feature_as_pattern) - env record_payload.subpat - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (PBinding { mut; mode; var; typ; subpat }, reduce_acc) - - method visit_pat (env : 'env) (this : pat) : pat * 'acc = - let p, reduce_acc = self#visit_pat' env this.p in - let span, reduce_acc' = self#visit_span env this.span in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let typ, reduce_acc' = self#visit_ty env this.typ in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let out : pat = { p; span; typ } in - (out, reduce_acc) - - method visit_field_pat (env : 'env) (this : field_pat) - : field_pat * 'acc = - let field, reduce_acc = self#visit_global_ident env this.field in - let pat, reduce_acc' = self#visit_pat env this.pat in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let out : field_pat = { field; pat } in - (out, reduce_acc) - - method visit_expr' (env : 'env) (this : expr') : expr' * 'acc = - match this with - | If record_payload -> - let cond, reduce_acc = self#visit_expr env record_payload.cond in - let then_, reduce_acc' = - self#visit_expr env record_payload.then_ - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let else_, reduce_acc' = - self#visit_option self#visit_expr env record_payload.else_ - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (If { cond; then_; else_ }, reduce_acc) - | App record_payload -> - let f, reduce_acc = self#visit_expr env record_payload.f in - let args, reduce_acc' = - self#visit_list self#visit_expr env record_payload.args - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let generic_args, reduce_acc' = - self#visit_list self#visit_generic_value env - record_payload.generic_args - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let bounds_impls, reduce_acc' = - self#visit_list self#visit_impl_expr env - record_payload.bounds_impls - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let impl, reduce_acc' = - self#visit_option self#visit_impl_expr env record_payload.impl - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (App { f; args; generic_args; impl; bounds_impls }, reduce_acc) - | Literal x0 -> - let x0, reduce_acc = self#visit_literal env x0 in - (Literal x0, reduce_acc) - | Array x0 -> - let x0, reduce_acc = self#visit_list self#visit_expr env x0 in - (Array x0, reduce_acc) - | Construct record_payload -> - let constructor, reduce_acc = - self#visit_global_ident env record_payload.constructor - in - let is_record, reduce_acc' = - self#visit_bool env record_payload.is_record - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let is_struct, reduce_acc' = - self#visit_bool env record_payload.is_struct - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let fields, reduce_acc' = - self#visit_list - (self#visit_tuple2 self#visit_global_ident self#visit_expr) - env record_payload.fields - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let base, reduce_acc' = - self#visit_option - (self#visit_tuple2 self#visit_expr - self#visit_feature_construct_base) - env record_payload.base - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - ( Construct { constructor; is_record; is_struct; fields; base }, - reduce_acc ) - | Match record_payload -> - let scrutinee, reduce_acc = - self#visit_expr env record_payload.scrutinee - in - let arms, reduce_acc' = - self#visit_list self#visit_arm env record_payload.arms - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (Match { scrutinee; arms }, reduce_acc) - | Let record_payload -> - let monadic, reduce_acc = - self#visit_option - (self#visit_tuple2 self#visit_supported_monads - self#visit_feature_monadic_binding) - env record_payload.monadic - in - let lhs, reduce_acc' = self#visit_pat env record_payload.lhs in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let rhs, reduce_acc' = self#visit_expr env record_payload.rhs in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let body, reduce_acc' = self#visit_expr env record_payload.body in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (Let { monadic; lhs; rhs; body }, reduce_acc) - | Block (x0, x1) -> - let x0, reduce_acc = self#visit_expr env x0 in - let x1, reduce_acc' = self#visit_feature_block env x1 in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (Block (x0, x1), reduce_acc) - | LocalVar x0 -> - let x0, reduce_acc = self#visit_local_ident env x0 in - (LocalVar x0, reduce_acc) - | GlobalVar x0 -> - let x0, reduce_acc = self#visit_global_ident env x0 in - (GlobalVar x0, reduce_acc) - | Ascription record_payload -> - let e, reduce_acc = self#visit_expr env record_payload.e in - let typ, reduce_acc' = self#visit_ty env record_payload.typ in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (Ascription { e; typ }, reduce_acc) - | MacroInvokation record_payload -> - let macro, reduce_acc = - self#visit_global_ident env record_payload.macro - in - let args, reduce_acc' = - self#visit_string env record_payload.args - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let witness, reduce_acc' = - self#visit_feature_macro env record_payload.witness - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (MacroInvokation { macro; args; witness }, reduce_acc) - | Assign record_payload -> - let lhs, reduce_acc = self#visit_lhs env record_payload.lhs in - let e, reduce_acc' = self#visit_expr env record_payload.e in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let witness, reduce_acc' = - self#visit_feature_mutable_variable env record_payload.witness - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (Assign { lhs; e; witness }, reduce_acc) - | Loop record_payload -> - let body, reduce_acc = self#visit_expr env record_payload.body in - let kind, reduce_acc' = - self#visit_loop_kind env record_payload.kind - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let state, reduce_acc' = - self#visit_option self#visit_loop_state env record_payload.state - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let label, reduce_acc' = - self#visit_option self#visit_string env record_payload.label - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let witness, reduce_acc' = - self#visit_feature_loop env record_payload.witness - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (Loop { body; kind; state; label; witness }, reduce_acc) - | Break record_payload -> - let e, reduce_acc = self#visit_expr env record_payload.e in - let label, reduce_acc' = - self#visit_option self#visit_string env record_payload.label - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let witness, reduce_acc' = - self#visit_tuple2 self#visit_feature_break - self#visit_feature_loop env record_payload.witness - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (Break { e; label; witness }, reduce_acc) - | Return record_payload -> - let e, reduce_acc = self#visit_expr env record_payload.e in - let witness, reduce_acc' = - self#visit_feature_early_exit env record_payload.witness - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (Return { e; witness }, reduce_acc) - | QuestionMark record_payload -> - let e, reduce_acc = self#visit_expr env record_payload.e in - let return_typ, reduce_acc' = - self#visit_ty env record_payload.return_typ - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let witness, reduce_acc' = - self#visit_feature_question_mark env record_payload.witness - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (QuestionMark { e; return_typ; witness }, reduce_acc) - | Continue record_payload -> - let e, reduce_acc = - self#visit_option - (self#visit_tuple2 self#visit_feature_state_passing_loop - self#visit_expr) - env record_payload.e - in - let label, reduce_acc' = - self#visit_option self#visit_string env record_payload.label - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let witness, reduce_acc' = - self#visit_tuple2 self#visit_feature_continue - self#visit_feature_loop env record_payload.witness - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (Continue { e; label; witness }, reduce_acc) - | Borrow record_payload -> - let kind, reduce_acc = - self#visit_borrow_kind env record_payload.kind - in - let e, reduce_acc' = self#visit_expr env record_payload.e in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let witness, reduce_acc' = - self#visit_feature_reference env record_payload.witness - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (Borrow { kind; e; witness }, reduce_acc) - | AddressOf record_payload -> - let mut, reduce_acc = - self#visit_mutability self#visit_feature_mutable_pointer env - record_payload.mut - in - let e, reduce_acc' = self#visit_expr env record_payload.e in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let witness, reduce_acc' = - self#visit_feature_raw_pointer env record_payload.witness - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (AddressOf { mut; e; witness }, reduce_acc) - | Closure record_payload -> - let params, reduce_acc = - self#visit_list self#visit_pat env record_payload.params - in - let body, reduce_acc' = self#visit_expr env record_payload.body in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let captures, reduce_acc' = - self#visit_list self#visit_expr env record_payload.captures - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (Closure { params; body; captures }, reduce_acc) - | EffectAction record_payload -> - let action, reduce_acc = - self#visit_feature_monadic_action env record_payload.action - in - let argument, reduce_acc' = - self#visit_expr env record_payload.argument - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (EffectAction { action; argument }, reduce_acc) - | Quote quote -> - let quote, acc = self#visit_quote env quote in - (Quote quote, acc) - - method visit_expr (env : 'env) (this : expr) : expr * 'acc = - let e, reduce_acc = self#visit_expr' env this.e in - let span, reduce_acc' = self#visit_span env this.span in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let typ, reduce_acc' = self#visit_ty env this.typ in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let out : expr = { e; span; typ } in - (out, reduce_acc) - - method visit_quote (env : 'env) ({ contents; witness } : quote) - : quote * 'acc = - let list, reduce_acc = - self#visit_list - (fun env -> function - | `Verbatim code -> (`Verbatim code, self#zero) - | `Expr e -> - let e, acc = self#visit_expr env e in - (`Expr e, acc) - | `Pat p -> - let p, acc = self#visit_pat env p in - (`Pat p, acc) - | `Typ t -> - let t, acc = self#visit_ty env t in - (`Typ t, acc)) - env contents - in - let witness, reduce_acc' = self#visit_feature_quote env witness in - let reduce_acc = self#plus reduce_acc reduce_acc' in - ({ contents; witness }, reduce_acc) - - method visit_supported_monads (env : 'env) (this : supported_monads) - : supported_monads * 'acc = - match this with - | MException x0 -> - let x0, reduce_acc = self#visit_ty env x0 in - (MException x0, reduce_acc) - | MResult x0 -> - let x0, reduce_acc = self#visit_ty env x0 in - (MResult x0, reduce_acc) - | MOption -> (MOption, self#zero) - - method visit_loop_kind (env : 'env) (this : loop_kind) - : loop_kind * 'acc = - match this with - | UnconditionalLoop -> (UnconditionalLoop, self#zero) - | WhileLoop record_payload -> - let condition, reduce_acc = - self#visit_expr env record_payload.condition - in - let witness, reduce_acc' = - self#visit_feature_while_loop env record_payload.witness - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (WhileLoop { condition; witness }, reduce_acc) - | ForLoop record_payload -> - let pat, reduce_acc = self#visit_pat env record_payload.pat in - let it, reduce_acc' = self#visit_expr env record_payload.it in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let witness, reduce_acc' = - self#visit_feature_for_loop env record_payload.witness - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (ForLoop { pat; it; witness }, reduce_acc) - | ForIndexLoop record_payload -> - let start, reduce_acc = - self#visit_expr env record_payload.start - in - let end_, reduce_acc' = self#visit_expr env record_payload.end_ in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let var, reduce_acc' = - self#visit_local_ident env record_payload.var - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let var_typ, reduce_acc' = - self#visit_ty env record_payload.var_typ - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let witness, reduce_acc' = - self#visit_feature_for_index_loop env record_payload.witness - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (ForIndexLoop { start; end_; var; var_typ; witness }, reduce_acc) - - method visit_loop_state (env : 'env) (this : loop_state) - : loop_state * 'acc = - let init, reduce_acc = self#visit_expr env this.init in - let bpat, reduce_acc' = self#visit_pat env this.bpat in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let witness, reduce_acc' = - self#visit_feature_state_passing_loop env this.witness - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let out : loop_state = { init; bpat; witness } in - (out, reduce_acc) - - method visit_lhs (env : 'env) (this : lhs) : lhs * 'acc = - match this with - | LhsLocalVar record_payload -> - let var, reduce_acc = - self#visit_local_ident env record_payload.var - in - let typ, reduce_acc' = self#visit_ty env record_payload.typ in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (LhsLocalVar { var; typ }, reduce_acc) - | LhsArbitraryExpr record_payload -> - let e, reduce_acc = self#visit_expr env record_payload.e in - let witness, reduce_acc' = - self#visit_feature_arbitrary_lhs env record_payload.witness - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (LhsArbitraryExpr { e; witness }, reduce_acc) - | LhsFieldAccessor record_payload -> - let e, reduce_acc = self#visit_lhs env record_payload.e in - let typ, reduce_acc' = self#visit_ty env record_payload.typ in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let field, reduce_acc' = - self#visit_global_ident env record_payload.field - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let witness, reduce_acc' = - self#visit_feature_nontrivial_lhs env record_payload.witness - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (LhsFieldAccessor { e; typ; field; witness }, reduce_acc) - | LhsArrayAccessor record_payload -> - let e, reduce_acc = self#visit_lhs env record_payload.e in - let typ, reduce_acc' = self#visit_ty env record_payload.typ in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let index, reduce_acc' = - self#visit_expr env record_payload.index - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let witness, reduce_acc' = - self#visit_feature_nontrivial_lhs env record_payload.witness - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (LhsArrayAccessor { e; typ; index; witness }, reduce_acc) - - method visit_arm' (env : 'env) (this : arm') : arm' * 'acc = - let arm_pat, reduce_acc = self#visit_pat env this.arm_pat in - let body, reduce_acc' = self#visit_expr env this.body in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let out : arm' = { arm_pat; body } in - (out, reduce_acc) - - method visit_arm (env : 'env) (this : arm) : arm * 'acc = - let arm, reduce_acc = self#visit_arm' env this.arm in - let span, reduce_acc' = self#visit_span env this.span in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let out : arm = { arm; span } in - (out, reduce_acc) - - method visit_generic_param (env : 'env) (this : generic_param) - : generic_param * 'acc = - let ident, reduce_acc = self#visit_local_ident env this.ident in - let span, reduce_acc' = self#visit_span env this.span in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let attrs, reduce_acc' = - self#visit_list self#visit_attr env this.attrs - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let kind, reduce_acc' = self#visit_generic_param_kind env this.kind in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let out : generic_param = { ident; span; attrs; kind } in - (out, reduce_acc) - - method visit_generic_param_kind (env : 'env) (this : generic_param_kind) - : generic_param_kind * 'acc = - match this with - | GPLifetime record_payload -> - let witness, reduce_acc = - self#visit_feature_lifetime env record_payload.witness - in - (GPLifetime { witness }, reduce_acc) - | GPType record_payload -> - let default, reduce_acc = - self#visit_option self#visit_ty env record_payload.default - in - (GPType { default }, reduce_acc) - | GPConst record_payload -> - let typ, reduce_acc = self#visit_ty env record_payload.typ in - (GPConst { typ }, reduce_acc) - - method visit_generic_constraint (env : 'env) (this : generic_constraint) - : generic_constraint * 'acc = - match this with - | GCLifetime (x0, x1) -> - let x0, reduce_acc = self#visit_todo env x0 in - let x1, reduce_acc' = self#visit_feature_lifetime env x1 in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (GCLifetime (x0, x1), reduce_acc) - | GCType x0 -> - let x0, reduce_acc = self#visit_impl_ident env x0 in - (GCType x0, reduce_acc) - - method visit_param (env : 'env) (this : param) : param * 'acc = - let pat, reduce_acc = self#visit_pat env this.pat in - let typ, reduce_acc' = self#visit_ty env this.typ in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let typ_span, reduce_acc' = - self#visit_option self#visit_span env this.typ_span - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let attrs, reduce_acc' = - self#visit_list self#visit_attr env this.attrs - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let out : param = { pat; typ; typ_span; attrs } in - (out, reduce_acc) - - method visit_generics (env : 'env) (this : generics) : generics * 'acc = - let params, reduce_acc = - self#visit_list self#visit_generic_param env this.params - in - let constraints, reduce_acc' = - self#visit_list self#visit_generic_constraint env this.constraints - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let out : generics = { params; constraints } in - (out, reduce_acc) - - method visit_variant (env : 'env) (this : variant) : variant * 'acc = - let name, reduce_acc = self#visit_concrete_ident env this.name in - let arguments, reduce_acc' = - self#visit_list - (self#visit_tuple3 self#visit_concrete_ident self#visit_ty - (self#visit_list self#visit_attr)) - env this.arguments - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let is_record, reduce_acc' = self#visit_bool env this.is_record in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let attrs, reduce_acc' = - self#visit_list self#visit_attr env this.attrs - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let out : variant = { name; arguments; is_record; attrs } in - (out, reduce_acc) - - method visit_item' (env : 'env) (this : item') : item' * 'acc = - match this with - | Fn record_payload -> - let name, reduce_acc = - self#visit_concrete_ident env record_payload.name - in - let generics, reduce_acc' = - self#visit_generics env record_payload.generics - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let body, reduce_acc' = self#visit_expr env record_payload.body in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let params, reduce_acc' = - self#visit_list self#visit_param env record_payload.params - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (Fn { name; generics; body; params }, reduce_acc) - | TyAlias record_payload -> - let name, reduce_acc = - self#visit_concrete_ident env record_payload.name - in - let generics, reduce_acc' = - self#visit_generics env record_payload.generics - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let ty, reduce_acc' = self#visit_ty env record_payload.ty in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (TyAlias { name; generics; ty }, reduce_acc) - | Type record_payload -> - let name, reduce_acc = - self#visit_concrete_ident env record_payload.name - in - let generics, reduce_acc' = - self#visit_generics env record_payload.generics - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let variants, reduce_acc' = - self#visit_list self#visit_variant env record_payload.variants - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let is_struct, reduce_acc' = - self#visit_bool env record_payload.is_struct - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (Type { name; generics; variants; is_struct }, reduce_acc) - | IMacroInvokation record_payload -> - let macro, reduce_acc = - self#visit_concrete_ident env record_payload.macro - in - let argument, reduce_acc' = - self#visit_string env record_payload.argument - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let span, reduce_acc' = self#visit_span env record_payload.span in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let witness, reduce_acc' = - self#visit_feature_macro env record_payload.witness - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (IMacroInvokation { macro; argument; span; witness }, reduce_acc) - | Trait record_payload -> - let name, reduce_acc = - self#visit_concrete_ident env record_payload.name - in - let generics, reduce_acc' = - self#visit_generics env record_payload.generics - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let items, reduce_acc' = - self#visit_list self#visit_trait_item env record_payload.items - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (Trait { name; generics; items }, reduce_acc) - | Impl record_payload -> - let generics, reduce_acc = - self#visit_generics env record_payload.generics - in - let self_ty, reduce_acc' = - self#visit_ty env record_payload.self_ty - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let of_trait, reduce_acc' = - self#visit_tuple2 self#visit_global_ident - (self#visit_list self#visit_generic_value) - env record_payload.of_trait - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let items, reduce_acc' = - self#visit_list self#visit_impl_item env record_payload.items - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let parent_bounds, reduce_acc' = - self#visit_list - (self#visit_tuple2 self#visit_impl_expr self#visit_impl_ident) - env record_payload.parent_bounds - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - ( Impl { generics; self_ty; of_trait; items; parent_bounds }, - reduce_acc ) - | Alias record_payload -> - let name, reduce_acc = - self#visit_concrete_ident env record_payload.name - in - let item, reduce_acc' = - self#visit_concrete_ident env record_payload.item - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (Alias { name; item }, reduce_acc) - | Use record_payload -> - let path, reduce_acc = - self#visit_list self#visit_string env record_payload.path - in - let is_external, reduce_acc' = - self#visit_bool env record_payload.is_external - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let rename, reduce_acc' = - self#visit_option self#visit_string env record_payload.rename - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (Use { path; is_external; rename }, reduce_acc) - | Quote quote -> - let quote, acc = self#visit_quote env quote in - (Quote quote, acc) - | HaxError x0 -> - let x0, reduce_acc = self#visit_string env x0 in - (HaxError x0, reduce_acc) - | NotImplementedYet -> (NotImplementedYet, self#zero) - - method visit_item (env : 'env) (this : item) : item * 'acc = - let v, reduce_acc = self#visit_item' env this.v in - let span, reduce_acc' = self#visit_span env this.span in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let ident, reduce_acc' = self#visit_concrete_ident env this.ident in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let attrs, reduce_acc' = - self#visit_list self#visit_attr env this.attrs - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let out : item = { v; span; ident; attrs } in - (out, reduce_acc) - - method visit_impl_item' (env : 'env) (this : impl_item') - : impl_item' * 'acc = - match this with - | IIType record_payload -> - let typ, reduce_acc = self#visit_ty env record_payload.typ in - let parent_bounds, reduce_acc' = - self#visit_list - (self#visit_tuple2 self#visit_impl_expr self#visit_impl_ident) - env record_payload.parent_bounds - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (IIType { typ; parent_bounds }, reduce_acc) - | IIFn record_payload -> - let body, reduce_acc = self#visit_expr env record_payload.body in - let params, reduce_acc' = - self#visit_list self#visit_param env record_payload.params - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - (IIFn { body; params }, reduce_acc) - - method visit_impl_item (env : 'env) (this : impl_item) - : impl_item * 'acc = - let ii_span, reduce_acc = self#visit_span env this.ii_span in - let ii_generics, reduce_acc' = - self#visit_generics env this.ii_generics - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let ii_v, reduce_acc' = self#visit_impl_item' env this.ii_v in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let ii_ident, reduce_acc' = - self#visit_concrete_ident env this.ii_ident - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let ii_attrs, reduce_acc' = - self#visit_list self#visit_attr env this.ii_attrs - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let out : impl_item = - { ii_span; ii_generics; ii_v; ii_ident; ii_attrs } - in - (out, reduce_acc) - - method visit_trait_item' (env : 'env) (this : trait_item') - : trait_item' * 'acc = - match this with - | TIType x0 -> - let x0, reduce_acc = - self#visit_list self#visit_impl_ident env x0 - in - (TIType x0, reduce_acc) - | TIFn x0 -> - let x0, reduce_acc = self#visit_ty env x0 in - (TIFn x0, reduce_acc) - - method visit_trait_item (env : 'env) (this : trait_item) - : trait_item * 'acc = - let ti_span, reduce_acc = self#visit_span env this.ti_span in - let ti_generics, reduce_acc' = - self#visit_generics env this.ti_generics - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let ti_v, reduce_acc' = self#visit_trait_item' env this.ti_v in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let ti_ident, reduce_acc' = - self#visit_concrete_ident env this.ti_ident - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let ti_attrs, reduce_acc' = - self#visit_list self#visit_attr env this.ti_attrs - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let out : trait_item = - { ti_span; ti_generics; ti_v; ti_ident; ti_attrs } - in - (out, reduce_acc) - - method visit_list - : 'a. ('env -> 'a -> 'a * 'acc) -> 'env -> 'a list -> 'a list * 'acc - = - fun v env -> - Base.List.fold_map ~init:self#zero ~f:(fun acc x -> - let x, acc' = v env x in - (self#plus acc acc', x)) - >> swap - - method visit_option - : 'a. - ('env -> 'a -> 'a * 'acc) -> 'env -> 'a option -> 'a option * 'acc - = - fun v env this -> - match this with - | None -> (None, self#zero) - | Some x -> - let x, acc = v env x in - (Some x, acc) - - method visit_tuple2 - : 'a 'b. - ('env -> 'a -> 'a * 'acc) -> - ('env -> 'b -> 'b * 'acc) -> - 'env -> - 'a * 'b -> - ('a * 'b) * 'acc = - fun vx vy env (x, y) -> - let x, acc = vx env x in - let y, acc' = vy env y in - let acc = self#plus acc acc' in - ((x, y), acc) - - method visit_tuple3 - : 'a 'b 'c. - ('env -> 'a -> 'a * 'acc) -> - ('env -> 'b -> 'b * 'acc) -> - ('env -> 'c -> 'c * 'acc) -> - 'env -> - 'a * 'b * 'c -> - ('a * 'b * 'c) * 'acc = - fun vx vy vz env (x, y, z) -> - let x, acc = vx env x in - let y, acc' = vy env y in - let acc = self#plus acc acc' in - let z, acc' = vz env z in - let acc = self#plus acc acc' in - ((x, y, z), acc) - - method visit_mutability - : 'a. - ('env -> 'a -> 'a * 'acc) -> - 'env -> - 'a mutability -> - 'a mutability * 'acc = - fun v env this -> (this, self#zero) - - method visit_todo : 'env -> todo -> todo * 'acc = - fun _ x -> (x, self#zero) - - method visit_string : 'env -> string -> string * 'acc = - fun _ x -> (x, self#zero) - - method visit_span : 'env -> span -> span * 'acc = - fun _ x -> (x, self#zero) - - method visit_local_ident : 'env -> local_ident -> local_ident * 'acc = - fun _ x -> (x, self#zero) - - method visit_global_ident : 'env -> global_ident -> global_ident * 'acc - = - fun _ x -> (x, self#zero) - - method visit_concrete_ident - : 'env -> concrete_ident -> concrete_ident * 'acc = - fun _ x -> (x, self#zero) - - method visit_char : 'env -> char -> char * 'acc = - fun _ x -> (x, self#zero) - - method visit_bool : 'env -> bool -> bool * 'acc = - fun _ x -> (x, self#zero) - - method visit_int_kind : 'env -> int_kind -> int_kind * 'acc = - fun _ x -> (x, self#zero) - - method visit_float_kind : 'env -> float_kind -> float_kind * 'acc = - fun _ x -> (x, self#zero) - - method visit_feature_mutable_reference - : 'env -> F.mutable_reference -> F.mutable_reference * 'acc = - fun _ x -> (x, self#zero) - - method visit_feature_reference - : 'env -> F.reference -> F.reference * 'acc = - fun _ x -> (x, self#zero) - - method visit_feature_slice : 'env -> F.slice -> F.slice * 'acc = - fun _ x -> (x, self#zero) - - method visit_feature_raw_pointer - : 'env -> F.raw_pointer -> F.raw_pointer * 'acc = - fun _ x -> (x, self#zero) - - method visit_feature_lifetime : 'env -> F.lifetime -> F.lifetime * 'acc - = - fun _ x -> (x, self#zero) - - method visit_feature_mutable_variable - : 'env -> F.mutable_variable -> F.mutable_variable * 'acc = - fun _ x -> (x, self#zero) - - method visit_feature_as_pattern - : 'env -> F.as_pattern -> F.as_pattern * 'acc = - fun _ x -> (x, self#zero) - - method visit_feature_construct_base - : 'env -> F.construct_base -> F.construct_base * 'acc = - fun _ x -> (x, self#zero) - - method visit_feature_monadic_binding - : 'env -> F.monadic_binding -> F.monadic_binding * 'acc = - fun _ x -> (x, self#zero) - - method visit_feature_block : 'env -> F.block -> F.block * 'acc = - fun _ x -> (x, self#zero) - - method visit_feature_macro : 'env -> F.macro -> F.macro * 'acc = - fun _ x -> (x, self#zero) - - method visit_feature_loop : 'env -> F.loop -> F.loop * 'acc = - fun _ x -> (x, self#zero) - - method visit_feature_break : 'env -> F.break -> F.break * 'acc = - fun _ x -> (x, self#zero) - - method visit_feature_early_exit - : 'env -> F.early_exit -> F.early_exit * 'acc = - fun _ x -> (x, self#zero) - - method visit_feature_question_mark - : 'env -> F.question_mark -> F.question_mark * 'acc = - fun _ x -> (x, self#zero) - - method visit_feature_state_passing_loop - : 'env -> F.state_passing_loop -> F.state_passing_loop * 'acc = - fun _ x -> (x, self#zero) - - method visit_feature_continue : 'env -> F.continue -> F.continue * 'acc - = - fun _ x -> (x, self#zero) - - method visit_feature_mutable_pointer - : 'env -> F.mutable_pointer -> F.mutable_pointer * 'acc = - fun _ x -> (x, self#zero) - - method visit_feature_monadic_action - : 'env -> F.monadic_action -> F.monadic_action * 'acc = - fun _ x -> (x, self#zero) - - method visit_feature_while_loop - : 'env -> F.while_loop -> F.while_loop * 'acc = - fun _ x -> (x, self#zero) - - method visit_feature_for_loop : 'env -> F.for_loop -> F.for_loop * 'acc - = - fun _ x -> (x, self#zero) - - method visit_feature_for_index_loop - : 'env -> F.for_index_loop -> F.for_index_loop * 'acc = - fun _ x -> (x, self#zero) - - method visit_feature_arbitrary_lhs - : 'env -> F.arbitrary_lhs -> F.arbitrary_lhs * 'acc = - fun _ x -> (x, self#zero) - - method visit_feature_nontrivial_lhs - : 'env -> F.nontrivial_lhs -> F.nontrivial_lhs * 'acc = - fun _ x -> (x, self#zero) - - method visit_feature_quote : 'env -> F.quote -> F.quote * 'acc = - fun _ x -> (x, self#zero) - end - - class virtual ['self] reduce = - object (self : 'self) - method visit_literal (env : 'env) (this : literal) : 'acc = - match this with - | String x0 -> - let reduce_acc = self#visit_string env x0 in - reduce_acc - | Char x0 -> - let reduce_acc = self#visit_char env x0 in - reduce_acc - | Int record_payload -> - let reduce_acc = self#visit_string env record_payload.value in - let reduce_acc' = self#visit_bool env record_payload.negative in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = self#visit_int_kind env record_payload.kind in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | Float record_payload -> - let reduce_acc = self#visit_string env record_payload.value in - let reduce_acc' = self#visit_bool env record_payload.negative in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = self#visit_float_kind env record_payload.kind in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | Bool x0 -> - let reduce_acc = self#visit_bool env x0 in - reduce_acc - - method visit_attr_kind (env : 'env) (this : attr_kind) : 'acc = - match this with - | Tool record_payload -> - let reduce_acc = self#visit_string env record_payload.path in - let reduce_acc' = self#visit_string env record_payload.tokens in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | DocComment record_payload -> - let reduce_acc = - self#visit_doc_comment_kind env record_payload.kind - in - let reduce_acc' = self#visit_string env record_payload.body in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - - method visit_attr (env : 'env) (this : attr) : 'acc = - let reduce_acc = self#visit_attr_kind env this.kind in - let reduce_acc' = self#visit_span env this.span in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - - method visit_doc_comment_kind (env : 'env) (this : doc_comment_kind) - : 'acc = - match this with DCKLine -> self#zero | DCKBlock -> self#zero - - method visit_borrow_kind (env : 'env) (this : borrow_kind) : 'acc = - match this with - | Shared -> self#zero - | Unique -> self#zero - | Mut x0 -> - let reduce_acc = self#visit_feature_mutable_reference env x0 in - reduce_acc - - method visit_binding_mode (env : 'env) (this : binding_mode) : 'acc = - match this with - | ByValue -> self#zero - | ByRef (x0, x1) -> - let reduce_acc = self#visit_borrow_kind env x0 in - let reduce_acc' = self#visit_feature_reference env x1 in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - - method visit_ty (env : 'env) (this : ty) : 'acc = - match this with - | TBool -> self#zero - | TChar -> self#zero - | TInt x0 -> - let reduce_acc = self#visit_int_kind env x0 in - reduce_acc - | TFloat x0 -> - let reduce_acc = self#visit_float_kind env x0 in - reduce_acc - | TStr -> self#zero - | TApp record_payload -> - let reduce_acc = - self#visit_global_ident env record_payload.ident - in - let reduce_acc' = - self#visit_list self#visit_generic_value env record_payload.args - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | TArray record_payload -> - let reduce_acc = self#visit_ty env record_payload.typ in - let reduce_acc' = self#visit_expr env record_payload.length in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | TSlice record_payload -> - let reduce_acc = - self#visit_feature_slice env record_payload.witness - in - let reduce_acc' = self#visit_ty env record_payload.ty in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | TRawPointer record_payload -> - let reduce_acc = - self#visit_feature_raw_pointer env record_payload.witness - in - reduce_acc - | TRef record_payload -> - let reduce_acc = - self#visit_feature_reference env record_payload.witness - in - let reduce_acc' = self#visit_todo env record_payload.region in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = self#visit_ty env record_payload.typ in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = - self#visit_mutability self#visit_feature_mutable_reference env - record_payload.mut - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | TParam x0 -> - let reduce_acc = self#visit_local_ident env x0 in - reduce_acc - | TArrow (x0, x1) -> - let reduce_acc = self#visit_list self#visit_ty env x0 in - let reduce_acc' = self#visit_ty env x1 in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | TAssociatedType record_payload -> - let reduce_acc = self#visit_impl_expr env record_payload.impl in - let reduce_acc' = - self#visit_concrete_ident env record_payload.item - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | TOpaque x0 -> - let reduce_acc = self#visit_concrete_ident env x0 in - reduce_acc - - method visit_generic_value (env : 'env) (this : generic_value) : 'acc = - match this with - | GLifetime record_payload -> - let reduce_acc = self#visit_todo env record_payload.lt in - let reduce_acc' = - self#visit_feature_lifetime env record_payload.witness - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | GType x0 -> - let reduce_acc = self#visit_ty env x0 in - reduce_acc - | GConst x0 -> - let reduce_acc = self#visit_expr env x0 in - reduce_acc - - method visit_impl_expr (env : 'env) (this : impl_expr) : 'acc = - match this with - | Self -> self#zero - | Concrete x0 -> - let reduce_acc = self#visit_trait_goal env x0 in - reduce_acc - | LocalBound record_payload -> - let reduce_acc = self#visit_string env record_payload.id in - reduce_acc - | Parent record_payload -> - let reduce_acc = self#visit_impl_expr env record_payload.impl in - let reduce_acc' = - self#visit_impl_ident env record_payload.ident - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | Projection record_payload -> - let reduce_acc = self#visit_impl_expr env record_payload.impl in - let reduce_acc' = - self#visit_impl_ident env record_payload.ident - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = - self#visit_concrete_ident env record_payload.item - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | ImplApp record_payload -> - let reduce_acc = self#visit_impl_expr env record_payload.impl in - let reduce_acc' = - self#visit_list self#visit_impl_expr env record_payload.args - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | Dyn -> self#zero - | Builtin x0 -> - let reduce_acc = self#visit_trait_goal env x0 in - reduce_acc - - method visit_trait_goal (env : 'env) (this : trait_goal) : 'acc = - let reduce_acc = self#visit_concrete_ident env this.trait in - let reduce_acc' = - self#visit_list self#visit_generic_value env this.args - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - - method visit_impl_ident (env : 'env) (this : impl_ident) : 'acc = - let reduce_acc = self#visit_trait_goal env this.goal in - reduce_acc - - method visit_pat' (env : 'env) (this : pat') : 'acc = - match this with - | PWild -> self#zero - | PAscription record_payload -> - let reduce_acc = self#visit_ty env record_payload.typ in - let reduce_acc' = self#visit_span env record_payload.typ_span in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = self#visit_pat env record_payload.pat in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | PConstruct record_payload -> - let reduce_acc = - self#visit_global_ident env record_payload.name - in - let reduce_acc' = - self#visit_list self#visit_field_pat env record_payload.args - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = self#visit_bool env record_payload.is_record in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = self#visit_bool env record_payload.is_struct in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | POr record_payload -> - let reduce_acc = - self#visit_list self#visit_pat env record_payload.subpats - in - reduce_acc - | PArray record_payload -> - let reduce_acc = - self#visit_list self#visit_pat env record_payload.args - in - reduce_acc - | PDeref record_payload -> - let reduce_acc = self#visit_pat env record_payload.subpat in - let reduce_acc' = - self#visit_feature_reference env record_payload.witness - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | PConstant record_payload -> - let reduce_acc = self#visit_literal env record_payload.lit in - reduce_acc - | PBinding record_payload -> - let reduce_acc = - self#visit_mutability self#visit_feature_mutable_variable env - record_payload.mut - in - let reduce_acc' = - self#visit_binding_mode env record_payload.mode - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = self#visit_local_ident env record_payload.var in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = self#visit_ty env record_payload.typ in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = - self#visit_option - (self#visit_tuple2 self#visit_pat - self#visit_feature_as_pattern) - env record_payload.subpat - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - - method visit_pat (env : 'env) (this : pat) : 'acc = - let reduce_acc = self#visit_pat' env this.p in - let reduce_acc' = self#visit_span env this.span in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = self#visit_ty env this.typ in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - - method visit_field_pat (env : 'env) (this : field_pat) : 'acc = - let reduce_acc = self#visit_global_ident env this.field in - let reduce_acc' = self#visit_pat env this.pat in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - - method visit_expr' (env : 'env) (this : expr') : 'acc = - match this with - | If record_payload -> - let reduce_acc = self#visit_expr env record_payload.cond in - let reduce_acc' = self#visit_expr env record_payload.then_ in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = - self#visit_option self#visit_expr env record_payload.else_ - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | App record_payload -> - let reduce_acc = self#visit_expr env record_payload.f in - let reduce_acc' = - self#visit_list self#visit_expr env record_payload.args - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = - self#visit_list self#visit_generic_value env - record_payload.generic_args - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = - self#visit_list self#visit_impl_expr env - record_payload.bounds_impls - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = - self#visit_option self#visit_impl_expr env record_payload.impl - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | Literal x0 -> - let reduce_acc = self#visit_literal env x0 in - reduce_acc - | Array x0 -> - let reduce_acc = self#visit_list self#visit_expr env x0 in - reduce_acc - | Construct record_payload -> - let reduce_acc = - self#visit_global_ident env record_payload.constructor - in - let reduce_acc' = self#visit_bool env record_payload.is_record in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = self#visit_bool env record_payload.is_struct in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = - self#visit_list - (self#visit_tuple2 self#visit_global_ident self#visit_expr) - env record_payload.fields - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = - self#visit_option - (self#visit_tuple2 self#visit_expr - self#visit_feature_construct_base) - env record_payload.base - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | Match record_payload -> - let reduce_acc = self#visit_expr env record_payload.scrutinee in - let reduce_acc' = - self#visit_list self#visit_arm env record_payload.arms - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | Let record_payload -> - let reduce_acc = - self#visit_option - (self#visit_tuple2 self#visit_supported_monads - self#visit_feature_monadic_binding) - env record_payload.monadic - in - let reduce_acc' = self#visit_pat env record_payload.lhs in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = self#visit_expr env record_payload.rhs in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = self#visit_expr env record_payload.body in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | Block (x0, x1) -> - let reduce_acc = self#visit_expr env x0 in - let reduce_acc' = self#visit_feature_block env x1 in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | LocalVar x0 -> - let reduce_acc = self#visit_local_ident env x0 in - reduce_acc - | GlobalVar x0 -> - let reduce_acc = self#visit_global_ident env x0 in - reduce_acc - | Ascription record_payload -> - let reduce_acc = self#visit_expr env record_payload.e in - let reduce_acc' = self#visit_ty env record_payload.typ in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | MacroInvokation record_payload -> - let reduce_acc = - self#visit_global_ident env record_payload.macro - in - let reduce_acc' = self#visit_string env record_payload.args in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = - self#visit_feature_macro env record_payload.witness - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | Assign record_payload -> - let reduce_acc = self#visit_lhs env record_payload.lhs in - let reduce_acc' = self#visit_expr env record_payload.e in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = - self#visit_feature_mutable_variable env record_payload.witness - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | Loop record_payload -> - let reduce_acc = self#visit_expr env record_payload.body in - let reduce_acc' = self#visit_loop_kind env record_payload.kind in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = - self#visit_option self#visit_loop_state env record_payload.state - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = - self#visit_option self#visit_string env record_payload.label - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = - self#visit_feature_loop env record_payload.witness - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | Break record_payload -> - let reduce_acc = self#visit_expr env record_payload.e in - let reduce_acc' = - self#visit_option self#visit_string env record_payload.label - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = - self#visit_tuple2 self#visit_feature_break - self#visit_feature_loop env record_payload.witness - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | Return record_payload -> - let reduce_acc = self#visit_expr env record_payload.e in - let reduce_acc' = - self#visit_feature_early_exit env record_payload.witness - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | QuestionMark record_payload -> - let reduce_acc = self#visit_expr env record_payload.e in - let reduce_acc' = self#visit_ty env record_payload.return_typ in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = - self#visit_feature_question_mark env record_payload.witness - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | Continue record_payload -> - let reduce_acc = - self#visit_option - (self#visit_tuple2 self#visit_feature_state_passing_loop - self#visit_expr) - env record_payload.e - in - let reduce_acc' = - self#visit_option self#visit_string env record_payload.label - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = - self#visit_tuple2 self#visit_feature_continue - self#visit_feature_loop env record_payload.witness - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | Borrow record_payload -> - let reduce_acc = self#visit_borrow_kind env record_payload.kind in - let reduce_acc' = self#visit_expr env record_payload.e in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = - self#visit_feature_reference env record_payload.witness - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | AddressOf record_payload -> - let reduce_acc = - self#visit_mutability self#visit_feature_mutable_pointer env - record_payload.mut - in - let reduce_acc' = self#visit_expr env record_payload.e in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = - self#visit_feature_raw_pointer env record_payload.witness - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | Closure record_payload -> - let reduce_acc = - self#visit_list self#visit_pat env record_payload.params - in - let reduce_acc' = self#visit_expr env record_payload.body in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = - self#visit_list self#visit_expr env record_payload.captures - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | EffectAction record_payload -> - let reduce_acc = - self#visit_feature_monadic_action env record_payload.action - in - let reduce_acc' = self#visit_expr env record_payload.argument in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | Quote quote -> self#visit_quote env quote - - method visit_expr (env : 'env) (this : expr) : 'acc = - let reduce_acc = self#visit_expr' env this.e in - let reduce_acc' = self#visit_span env this.span in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = self#visit_ty env this.typ in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - - method visit_quote (env : 'env) ({ contents; witness } : quote) : 'acc = - let reduce_acc = - self#visit_list - (fun env -> function - | `Verbatim code -> self#zero - | `Expr e -> self#visit_expr env e - | `Pat p -> self#visit_pat env p - | `Typ t -> self#visit_ty env t) - env contents - in - let reduce_acc' = self#visit_feature_quote env witness in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - - method visit_supported_monads (env : 'env) (this : supported_monads) - : 'acc = - match this with - | MException x0 -> - let reduce_acc = self#visit_ty env x0 in - reduce_acc - | MResult x0 -> - let reduce_acc = self#visit_ty env x0 in - reduce_acc - | MOption -> self#zero - - method visit_loop_kind (env : 'env) (this : loop_kind) : 'acc = - match this with - | UnconditionalLoop -> self#zero - | WhileLoop record_payload -> - let reduce_acc = self#visit_expr env record_payload.condition in - let reduce_acc' = - self#visit_feature_while_loop env record_payload.witness - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | ForLoop record_payload -> - let reduce_acc = self#visit_pat env record_payload.pat in - let reduce_acc' = self#visit_expr env record_payload.it in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = - self#visit_feature_for_loop env record_payload.witness - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | ForIndexLoop record_payload -> - let reduce_acc = self#visit_expr env record_payload.start in - let reduce_acc' = self#visit_expr env record_payload.end_ in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = self#visit_local_ident env record_payload.var in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = self#visit_ty env record_payload.var_typ in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = - self#visit_feature_for_index_loop env record_payload.witness - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - - method visit_loop_state (env : 'env) (this : loop_state) : 'acc = - let reduce_acc = self#visit_expr env this.init in - let reduce_acc' = self#visit_pat env this.bpat in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = - self#visit_feature_state_passing_loop env this.witness - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - - method visit_lhs (env : 'env) (this : lhs) : 'acc = - match this with - | LhsLocalVar record_payload -> - let reduce_acc = self#visit_local_ident env record_payload.var in - let reduce_acc' = self#visit_ty env record_payload.typ in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | LhsArbitraryExpr record_payload -> - let reduce_acc = self#visit_expr env record_payload.e in - let reduce_acc' = - self#visit_feature_arbitrary_lhs env record_payload.witness - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | LhsFieldAccessor record_payload -> - let reduce_acc = self#visit_lhs env record_payload.e in - let reduce_acc' = self#visit_ty env record_payload.typ in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = - self#visit_global_ident env record_payload.field - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = - self#visit_feature_nontrivial_lhs env record_payload.witness - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | LhsArrayAccessor record_payload -> - let reduce_acc = self#visit_lhs env record_payload.e in - let reduce_acc' = self#visit_ty env record_payload.typ in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = self#visit_expr env record_payload.index in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = - self#visit_feature_nontrivial_lhs env record_payload.witness - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - - method visit_arm' (env : 'env) (this : arm') : 'acc = - let reduce_acc = self#visit_pat env this.arm_pat in - let reduce_acc' = self#visit_expr env this.body in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - - method visit_arm (env : 'env) (this : arm) : 'acc = - let reduce_acc = self#visit_arm' env this.arm in - let reduce_acc' = self#visit_span env this.span in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - - method visit_generic_param (env : 'env) (this : generic_param) : 'acc = - let reduce_acc = self#visit_local_ident env this.ident in - let reduce_acc' = self#visit_span env this.span in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = self#visit_list self#visit_attr env this.attrs in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = self#visit_generic_param_kind env this.kind in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - - method visit_generic_param_kind (env : 'env) (this : generic_param_kind) - : 'acc = - match this with - | GPLifetime record_payload -> - let reduce_acc = - self#visit_feature_lifetime env record_payload.witness - in - reduce_acc - | GPType record_payload -> - let reduce_acc = - self#visit_option self#visit_ty env record_payload.default - in - reduce_acc - | GPConst record_payload -> - let reduce_acc = self#visit_ty env record_payload.typ in - reduce_acc - - method visit_generic_constraint (env : 'env) (this : generic_constraint) - : 'acc = - match this with - | GCLifetime (x0, x1) -> - let reduce_acc = self#visit_todo env x0 in - let reduce_acc' = self#visit_feature_lifetime env x1 in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | GCType x0 -> - let reduce_acc = self#visit_impl_ident env x0 in - reduce_acc - - method visit_param (env : 'env) (this : param) : 'acc = - let reduce_acc = self#visit_pat env this.pat in - let reduce_acc' = self#visit_ty env this.typ in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = - self#visit_option self#visit_span env this.typ_span - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = self#visit_list self#visit_attr env this.attrs in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - - method visit_generics (env : 'env) (this : generics) : 'acc = - let reduce_acc = - self#visit_list self#visit_generic_param env this.params - in - let reduce_acc' = - self#visit_list self#visit_generic_constraint env this.constraints - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - - method visit_variant (env : 'env) (this : variant) : 'acc = - let reduce_acc = self#visit_concrete_ident env this.name in - let reduce_acc' = - self#visit_list - (self#visit_tuple3 self#visit_concrete_ident self#visit_ty - (self#visit_list self#visit_attr)) - env this.arguments - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = self#visit_bool env this.is_record in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = self#visit_list self#visit_attr env this.attrs in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - - method visit_item' (env : 'env) (this : item') : 'acc = - match this with - | Fn record_payload -> - let reduce_acc = - self#visit_concrete_ident env record_payload.name - in - let reduce_acc' = - self#visit_generics env record_payload.generics - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = self#visit_expr env record_payload.body in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = - self#visit_list self#visit_param env record_payload.params - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | TyAlias record_payload -> - let reduce_acc = - self#visit_concrete_ident env record_payload.name - in - let reduce_acc' = - self#visit_generics env record_payload.generics - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = self#visit_ty env record_payload.ty in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | Type record_payload -> - let reduce_acc = - self#visit_concrete_ident env record_payload.name - in - let reduce_acc' = - self#visit_generics env record_payload.generics - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = - self#visit_list self#visit_variant env record_payload.variants - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = self#visit_bool env record_payload.is_struct in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | IMacroInvokation record_payload -> - let reduce_acc = - self#visit_concrete_ident env record_payload.macro - in - let reduce_acc' = self#visit_string env record_payload.argument in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = self#visit_span env record_payload.span in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = - self#visit_feature_macro env record_payload.witness - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | Trait record_payload -> - let reduce_acc = - self#visit_concrete_ident env record_payload.name - in - let reduce_acc' = - self#visit_generics env record_payload.generics - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = - self#visit_list self#visit_trait_item env record_payload.items - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | Impl record_payload -> - let reduce_acc = - self#visit_generics env record_payload.generics - in - let reduce_acc' = self#visit_ty env record_payload.self_ty in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = - self#visit_tuple2 self#visit_global_ident - (self#visit_list self#visit_generic_value) - env record_payload.of_trait - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = - self#visit_list self#visit_impl_item env record_payload.items - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = - self#visit_list - (self#visit_tuple2 self#visit_impl_expr self#visit_impl_ident) - env record_payload.parent_bounds - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | Alias record_payload -> - let reduce_acc = - self#visit_concrete_ident env record_payload.name - in - let reduce_acc' = - self#visit_concrete_ident env record_payload.item - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | Use record_payload -> - let reduce_acc = - self#visit_list self#visit_string env record_payload.path - in - let reduce_acc' = - self#visit_bool env record_payload.is_external - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = - self#visit_option self#visit_string env record_payload.rename - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | Quote quote -> self#visit_quote env quote - | HaxError x0 -> - let reduce_acc = self#visit_string env x0 in - reduce_acc - | NotImplementedYet -> self#zero - - method visit_item (env : 'env) (this : item) : 'acc = - let reduce_acc = self#visit_item' env this.v in - let reduce_acc' = self#visit_span env this.span in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = self#visit_concrete_ident env this.ident in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = self#visit_list self#visit_attr env this.attrs in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - - method visit_impl_item' (env : 'env) (this : impl_item') : 'acc = - match this with - | IIType record_payload -> - let reduce_acc = self#visit_ty env record_payload.typ in - let reduce_acc' = - self#visit_list - (self#visit_tuple2 self#visit_impl_expr self#visit_impl_ident) - env record_payload.parent_bounds - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - | IIFn record_payload -> - let reduce_acc = self#visit_expr env record_payload.body in - let reduce_acc' = - self#visit_list self#visit_param env record_payload.params - in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - - method visit_impl_item (env : 'env) (this : impl_item) : 'acc = - let reduce_acc = self#visit_span env this.ii_span in - let reduce_acc' = self#visit_generics env this.ii_generics in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = self#visit_impl_item' env this.ii_v in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = self#visit_concrete_ident env this.ii_ident in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = self#visit_list self#visit_attr env this.ii_attrs in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - - method visit_trait_item' (env : 'env) (this : trait_item') : 'acc = - match this with - | TIType x0 -> - let reduce_acc = self#visit_list self#visit_impl_ident env x0 in - reduce_acc - | TIFn x0 -> - let reduce_acc = self#visit_ty env x0 in - reduce_acc - - method visit_trait_item (env : 'env) (this : trait_item) : 'acc = - let reduce_acc = self#visit_span env this.ti_span in - let reduce_acc' = self#visit_generics env this.ti_generics in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = self#visit_trait_item' env this.ti_v in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = self#visit_concrete_ident env this.ti_ident in - let reduce_acc = self#plus reduce_acc reduce_acc' in - let reduce_acc' = self#visit_list self#visit_attr env this.ti_attrs in - let reduce_acc = self#plus reduce_acc reduce_acc' in - reduce_acc - - method visit_list : 'a. ('env -> 'a -> 'acc) -> 'env -> 'a list -> 'acc - = - fun v env this -> - Base.List.fold ~init:self#zero - ~f:(fun acc -> v env >> self#plus acc) - this - - method visit_option - : 'a. ('env -> 'a -> 'acc) -> 'env -> 'a option -> 'acc = - fun v env this -> - match this with - | None -> self#zero - | Some x -> - let acc = v env x in - acc - - method visit_tuple2 - : 'a 'b. - ('env -> 'a -> 'acc) -> - ('env -> 'b -> 'acc) -> - 'env -> - 'a * 'b -> - 'acc = - fun vx vy env (x, y) -> - let acc = vx env x in - let acc' = vy env y in - let acc = self#plus acc acc' in - acc - - method visit_tuple3 - : 'a 'b 'c. - ('env -> 'a -> 'acc) -> - ('env -> 'b -> 'acc) -> - ('env -> 'c -> 'acc) -> - 'env -> - 'a * 'b * 'c -> - 'acc = - fun vx vy vz env (x, y, z) -> - let acc = vx env x in - let acc' = vy env y in - let acc = self#plus acc acc' in - let acc' = vz env z in - let acc = self#plus acc acc' in - acc - - method visit_mutability - : 'a. ('env -> 'a -> 'acc) -> 'env -> 'a mutability -> 'acc = - fun v env this -> self#zero - - method visit_todo : 'env -> todo -> 'acc = fun _ _ -> self#zero - method visit_string : 'env -> string -> 'acc = fun _ _ -> self#zero - method visit_span : 'env -> span -> 'acc = fun _ _ -> self#zero - - method visit_local_ident : 'env -> local_ident -> 'acc = - fun _ _ -> self#zero - - method visit_global_ident : 'env -> global_ident -> 'acc = - fun _ _ -> self#zero - - method visit_concrete_ident : 'env -> concrete_ident -> 'acc = - fun _ _ -> self#zero - - method visit_char : 'env -> char -> 'acc = fun _ _ -> self#zero - method visit_bool : 'env -> bool -> 'acc = fun _ _ -> self#zero - method visit_int_kind : 'env -> int_kind -> 'acc = fun _ _ -> self#zero - - method visit_float_kind : 'env -> float_kind -> 'acc = - fun _ _ -> self#zero - - method visit_feature_mutable_reference - : 'env -> F.mutable_reference -> 'acc = - fun _ _ -> self#zero - - method visit_feature_reference : 'env -> F.reference -> 'acc = - fun _ _ -> self#zero - - method visit_feature_slice : 'env -> F.slice -> 'acc = - fun _ _ -> self#zero - - method visit_feature_raw_pointer : 'env -> F.raw_pointer -> 'acc = - fun _ _ -> self#zero - - method visit_feature_lifetime : 'env -> F.lifetime -> 'acc = - fun _ _ -> self#zero - - method visit_feature_mutable_variable - : 'env -> F.mutable_variable -> 'acc = - fun _ _ -> self#zero - - method visit_feature_as_pattern : 'env -> F.as_pattern -> 'acc = - fun _ _ -> self#zero - - method visit_feature_construct_base : 'env -> F.construct_base -> 'acc = - fun _ _ -> self#zero - - method visit_feature_monadic_binding : 'env -> F.monadic_binding -> 'acc - = - fun _ _ -> self#zero - - method visit_feature_block : 'env -> F.block -> 'acc = - fun _ _ -> self#zero - - method visit_feature_macro : 'env -> F.macro -> 'acc = - fun _ _ -> self#zero - - method visit_feature_loop : 'env -> F.loop -> 'acc = - fun _ _ -> self#zero - - method visit_feature_break : 'env -> F.break -> 'acc = - fun _ _ -> self#zero - - method visit_feature_early_exit : 'env -> F.early_exit -> 'acc = - fun _ _ -> self#zero - - method visit_feature_question_mark : 'env -> F.question_mark -> 'acc = - fun _ _ -> self#zero - - method visit_feature_state_passing_loop - : 'env -> F.state_passing_loop -> 'acc = - fun _ _ -> self#zero - - method visit_feature_continue : 'env -> F.continue -> 'acc = - fun _ _ -> self#zero - - method visit_feature_mutable_pointer : 'env -> F.mutable_pointer -> 'acc - = - fun _ _ -> self#zero - - method visit_feature_monadic_action : 'env -> F.monadic_action -> 'acc = - fun _ _ -> self#zero - - method visit_feature_while_loop : 'env -> F.while_loop -> 'acc = - fun _ _ -> self#zero - - method visit_feature_for_loop : 'env -> F.for_loop -> 'acc = - fun _ _ -> self#zero - - method visit_feature_for_index_loop : 'env -> F.for_index_loop -> 'acc = - fun _ _ -> self#zero - - method visit_feature_arbitrary_lhs : 'env -> F.arbitrary_lhs -> 'acc = - fun _ _ -> self#zero - - method visit_feature_nontrivial_lhs : 'env -> F.nontrivial_lhs -> 'acc = - fun _ _ -> self#zero - - method visit_feature_quote : 'env -> F.quote -> 'acc = - fun _ _ -> self#zero - end - end diff --git a/engine/lib/attr_payloads.ml b/engine/lib/attr_payloads.ml index 36964e184..61cbcd855 100644 --- a/engine/lib/attr_payloads.ml +++ b/engine/lib/attr_payloads.ml @@ -162,10 +162,11 @@ module Make (F : Features.T) (Error : Phase_utils.ERROR) = struct ?keep_last_args:int -> generics * param list * expr -> expr val associated_expr_rebinding : - pat list -> AssocRole.t -> attrs -> expr option + span -> pat list -> AssocRole.t -> attrs -> expr option (** Looks up an expression but takes care of rebinding free variables. *) - val associated_refinement_in_type : string list -> attrs -> expr option + val associated_refinement_in_type : + span -> string list -> attrs -> expr option (** For type, there is a special treatment. The name of fields are global identifiers, and thus are subject to rewriting by [Concrete_ident] at the moment of printing. In contrast, in the @@ -276,7 +277,7 @@ module Make (F : Features.T) (Error : Phase_utils.ERROR) = struct attrs -> expr list = associated_fns role >> List.map ~f:(expect_expr ~keep_last_args) - let associated_expr_rebinding (params : pat list) (role : AssocRole.t) + let associated_expr_rebinding span (params : pat list) (role : AssocRole.t) (attrs : attrs) : expr option = let* _, original_params, body = associated_fn role attrs in let original_params = @@ -287,9 +288,37 @@ module Make (F : Features.T) (Error : Phase_utils.ERROR) = struct in let original_vars = List.concat_map ~f:vars_of_pat original_params in let target_vars = List.concat_map ~f:vars_of_pat params in + let mk_error_message prefix = + prefix ^ "\n" ^ "\n - original_vars: " + ^ [%show: local_ident list] original_vars + ^ "\n - target_vars: " + ^ [%show: local_ident list] target_vars + ^ "\n\n - original_params: " + ^ [%show: pat list] original_params + ^ "\n - params: " + ^ [%show: pat list] params + in + let replacements = + List.zip_opt original_vars target_vars + |> Option.value_or_thunk ~default:(fun _ -> + let details = + mk_error_message + "associated_expr_rebinding: zip two lists of different \ + lengths (original_vars and target_vars)" + in + Error.unimplemented ~details span) + in let replacements = - List.zip_exn original_vars target_vars - |> Map.of_alist_exn (module Local_ident) + match Map.of_alist (module Local_ident) replacements with + | `Ok replacements -> replacements + | `Duplicate_key key -> + let details = + mk_error_message + "associated_expr_rebinding: of_alist failed because `" + ^ [%show: local_ident] key + ^ "` is a duplicate key. Context: " + in + Error.unimplemented ~details span in Some ((U.Mappers.rename_local_idents (fun v -> @@ -297,14 +326,25 @@ module Make (F : Features.T) (Error : Phase_utils.ERROR) = struct #visit_expr () body) - let associated_refinement_in_type (free_variables : string list) : + let associated_refinement_in_type span (free_variables : string list) : attrs -> expr option = associated_fn Refine >> Option.map ~f:(fun (_, params, body) -> let substs = - List.zip_exn - (List.concat_map ~f:U.Reducers.variables_of_param params) - (List.map ~f:Local_ident.make_final free_variables) + let x = + List.concat_map ~f:U.Reducers.variables_of_param params + in + let y = List.map ~f:Local_ident.make_final free_variables in + List.zip_opt x y + |> Option.value_or_thunk ~default:(fun _ -> + let details = + "associated_refinement_in_type: zip two lists of \ + different lenghts\n" ^ "\n - params: " + ^ [%show: param list] params + ^ "\n - free_variables: " + ^ [%show: string list] free_variables + in + Error.unimplemented ~details span) in let v = U.Mappers.rename_local_idents (fun i -> diff --git a/engine/lib/concrete_ident/concrete_ident.ml b/engine/lib/concrete_ident/concrete_ident.ml index 9ed4bda07..c8a1a49ec 100644 --- a/engine/lib/concrete_ident/concrete_ident.ml +++ b/engine/lib/concrete_ident/concrete_ident.ml @@ -15,11 +15,11 @@ module Imported = struct | ForeignMod | Use | GlobalAsm - | ClosureExpr + | Closure | Ctor | AnonConst - | ImplTrait - | ImplTraitAssocTy + | AnonAdt + | OpaqueTy | TypeNs of string | ValueNs of string | MacroNs of string @@ -32,15 +32,15 @@ module Imported = struct | ForeignMod -> ForeignMod | Use -> Use | GlobalAsm -> GlobalAsm - | ClosureExpr -> ClosureExpr + | Closure -> Closure | Ctor -> Ctor | AnonConst -> AnonConst - | ImplTrait -> ImplTrait - | ImplTraitAssocTy -> ImplTraitAssocTy + | OpaqueTy -> OpaqueTy | TypeNs s -> TypeNs s | ValueNs s -> ValueNs s | MacroNs s -> MacroNs s | LifetimeNs s -> LifetimeNs s + | AnonAdt -> AnonAdt let of_disambiguated_def_path_item : Types.disambiguated_def_path_item -> disambiguated_def_path_item = diff --git a/engine/lib/concrete_ident/impl_infos.ml b/engine/lib/concrete_ident/impl_infos.ml index 57a6a915c..175d058d1 100644 --- a/engine/lib/concrete_ident/impl_infos.ml +++ b/engine/lib/concrete_ident/impl_infos.ml @@ -32,6 +32,7 @@ let lookup span (impl : Concrete_ident.t) : t option = Import_thir.import_clause span binder in List.filter_map ~f clauses - |> List.map ~f:(fun (i : Ast.Rust.impl_ident) -> i.goal) + |> List.filter_map ~f:(fun (c : Ast.Rust.generic_constraint) -> + match c with GCType i -> Some i.goal | _ -> None) in Some { trait_goal; typ; clauses } diff --git a/engine/lib/diagnostics.ml b/engine/lib/diagnostics.ml index f0496d106..5079e3dfe 100644 --- a/engine/lib/diagnostics.ml +++ b/engine/lib/diagnostics.ml @@ -15,6 +15,8 @@ module Phase = struct | RawOrMutPointer | EarlyExit | AsPattern + | Dyn + | TraitItemDefault [@@deriving show { with_path = false }, eq, yojson, compare, hash, sexp] let display = function @@ -29,7 +31,9 @@ module Phase = struct | DropReferences | DropBlocks | DropSizedTrait + | DropMatchGuards | RefMut + | ResugarAsserts | ResugarForLoops | ResugarWhileLoops | ResugarForIndexLoops @@ -37,6 +41,7 @@ module Phase = struct | SimplifyQuestionMarks | Specialize | HoistSideEffects + | HoistDisjunctions | LocalMutation | TrivializeAssignLhs | CfIntoMonads @@ -91,19 +96,18 @@ let compare_thir_span (a : thir_span) (b : thir_span) = type t = { context : Context.t; kind : kind; span : thir_span list } [@@deriving show, eq, compare] -let to_thir_diagnostic (d : t) : Types.diagnostics_for__array_of__span = +let to_thir_diagnostic (d : t) : Types.diagnostics = { kind = d.kind; context = Context.display d.context; span = d.span } -let run_hax_pretty_print_diagnostics (s : string) : string = - try (Utils.Command.run "hax-pretty-print-diagnostics" s).stdout - with e -> - "[run_hax_pretty_print_diagnostics] failed. Exn: " - ^ "[run_hax_pretty_print_diagnostics] failed. Exn: " ^ Exn.to_string e - ^ ". Here is the JSON representation of the error that occurred:\n" ^ s +(** Ask `cargo-hax` to pretty print a diagnostic *) +let ask_diagnostic_pretty_print diag : string = + Hax_io.request (PrettyPrintDiagnostic diag) + ~expected:"PrettyPrintedDiagnostic" (function + | Types.PrettyPrintedDiagnostic s -> Some s + | _ -> None) let pretty_print : t -> string = - to_thir_diagnostic >> Types.to_json_diagnostics_for__array_of__span - >> Yojson.Safe.pretty_to_string >> run_hax_pretty_print_diagnostics + to_thir_diagnostic >> ask_diagnostic_pretty_print let pretty_print_context_kind : Context.t -> kind -> string = fun context kind -> diff --git a/engine/lib/dune b/engine/lib/dune index 5c73e0d79..149ea13e6 100644 --- a/engine/lib/dune +++ b/engine/lib/dune @@ -46,6 +46,17 @@ universe-hash (run bash %{universe_hash})))) +(rule + (target ast_visitors.ml) + (deps + (:ast ast.ml)) + (action + (with-stdout-to + ast_visitors.ml + (with-stdin-from + %{ast} + (run generate_visitors))))) + (rule (target concrete_ident_generated.ml) (deps diff --git a/engine/lib/features.ml b/engine/lib/features.ml index 260c08d0e..82be3dc1d 100644 --- a/engine/lib/features.ml +++ b/engine/lib/features.ml @@ -23,7 +23,10 @@ loop, monadic_action, monadic_binding, quote, - block] + block, + dyn, + match_guard, + trait_item_default] module Full = On diff --git a/engine/lib/generic_printer/generic_printer.ml b/engine/lib/generic_printer/generic_printer.ml index 1193c8e3a..c336f0b58 100644 --- a/engine/lib/generic_printer/generic_printer.ml +++ b/engine/lib/generic_printer/generic_printer.ml @@ -66,8 +66,7 @@ module Make (F : Features.T) (View : Concrete_ident.VIEW_API) = struct | Float { value; kind; negative } -> string value |> precede (if negative then minus else empty) - |> terminate - (string (match kind with F32 -> "f32" | F64 -> "f64")) + |> terminate (string (show_float_kind kind)) | Bool b -> OCaml.bool b method generic_value : generic_value fn = @@ -101,8 +100,7 @@ module Make (F : Features.T) (View : Concrete_ident.VIEW_API) = struct in string signedness ^^ size - method ty_float : float_kind fn = - (function F32 -> "f32" | F64 -> "f64") >> string + method ty_float : float_kind fn = show_float_kind >> string method generic_values : generic_value list fn = function @@ -143,6 +141,7 @@ module Make (F : Features.T) (View : Concrete_ident.VIEW_API) = struct | TAssociatedType _ -> string "assoc_type!()" | TOpaque _ -> string "opaque_type!()" | TApp _ -> super#ty ctx ty + | TDyn _ -> empty (* TODO *) method! expr' : par_state -> expr' fn = fun ctx e -> @@ -430,11 +429,20 @@ module Make (F : Features.T) (View : Concrete_ident.VIEW_API) = struct method generic_params : generic_param list fn = separate_map comma print#generic_param >> group >> angles + (*Option.map ~f:(...) guard |> Option.value ~default:empty*) method arm' : arm' fn = - fun { arm_pat; body } -> + fun { arm_pat; body; guard } -> let pat = print#pat_at Arm_pat arm_pat |> group in let body = print#expr_at Arm_body body in - pat ^^ string " => " ^^ body ^^ comma + let guard = + Option.map + ~f:(fun { guard = IfLet { lhs; rhs; _ }; _ } -> + string " if let " ^^ print#pat_at Arm_pat lhs ^^ string " = " + ^^ print#expr_at Arm_body rhs) + guard + |> Option.value ~default:empty + in + pat ^^ guard ^^ string " => " ^^ body ^^ comma end end diff --git a/engine/lib/hax_io.ml b/engine/lib/hax_io.ml new file mode 100644 index 000000000..af50a0615 --- /dev/null +++ b/engine/lib/hax_io.ml @@ -0,0 +1,59 @@ +open Prelude + +module type S = sig + val read_json : unit -> Yojson.Safe.t option + val write_json : Yojson.Safe.t -> unit +end + +include ( + struct + (** Contains the module *) + let state = ref None + + let init (module M : S) = state := Some (module M : S) + + let get () : (module S) = + !state + |> Option.value_exn + ~message:"Hax engine: internal error: Hax_io as not initialized" + + let read_json () = + let (module M) = get () in + M.read_json () + + let write_json json = + let (module M) = get () in + M.write_json json + end : + sig + include S + + val init : (module S) -> unit + end) + +let read () : Types.to_engine = + read_json () |> Option.value_exn |> Types.parse_to_engine + +let write (msg : Types.from_engine) : unit = + Types.to_json_from_engine msg |> write_json + +let close () : unit = + write Exit; + (* Ensure no garbadge collect *) + let _ = read_json () in + () + +let request (type a) ~expected (msg : Types.from_engine) + (filter : Types.to_engine -> a option) : a = + write msg; + let response = read () in + match filter response with + | Some value -> value + | None -> + let error = + "Internal error: communication protocol error between `hax-engine` and \ + `cargo-hax`. Expected `" ^ expected ^ "`, got `" + ^ [%show: Types.to_engine] response + ^ "` instead." + in + failwith error diff --git a/engine/lib/import_thir.ml b/engine/lib/import_thir.ml index bf4f5c323..852153147 100644 --- a/engine/lib/import_thir.ml +++ b/engine/lib/import_thir.ml @@ -79,12 +79,13 @@ let c_mutability (witness : 'a) : bool -> 'a Ast.mutability = function let c_borrow_kind span : Thir.borrow_kind -> borrow_kind = function | Shared -> Shared - | Shallow -> unimplemented [ span ] "Shallow borrows" + | Fake _ -> unimplemented [ span ] "Shallow borrows" | Mut _ -> Mut W.mutable_reference -let c_binding_mode span : Thir.binding_mode -> binding_mode = function - | ByValue -> ByValue - | ByRef k -> ByRef (c_borrow_kind span k, W.reference) +let c_binding_mode : Thir.by_ref -> binding_mode = function + | No -> ByValue + | Yes true -> ByRef (Mut W.mutable_reference, W.reference) + | Yes false -> ByRef (Shared, W.reference) let unit_typ : ty = TApp { ident = `TupleType 0; args = [] } @@ -108,12 +109,12 @@ let c_attr (attr : Thir.attribute) : attr = | Normal { item = - { args = Eq (_, Hir { symbol; _ }); path = "doc"; tokens = None }; + { args = Eq (_, Hir { symbol; _ }); path = "doc"; tokens = None; _ }; tokens = None; } -> DocComment { kind = DCKLine; body = symbol } (* Looks for `#[doc = "something"]` *) - | Normal { item = { args; path; tokens = subtokens }; tokens } -> + | Normal { item = { args; path; tokens = subtokens; _ }; tokens } -> let args_tokens = match args with Delimited { tokens; _ } -> Some tokens | _ -> None in @@ -161,7 +162,7 @@ let c_lit' span negative (lit : Thir.lit_kind) (ty : ty) : extended_literal = ^ "] instead.") in match lit with - | Err -> + | Err _ -> assertion_failure [ span ] "[import_thir:literal] got an error literal: this means the Rust \ compiler or Hax's frontend probably reported errors above." @@ -197,7 +198,7 @@ let resugar_index_mut (e : expr) : (expr * expr) option = f = { e = GlobalVar (`Concrete meth); _ }; args = [ { e = Borrow { e = x; _ }; _ }; index ]; generic_args = _ (* TODO: see issue #328 *); - impl = _ (* TODO: see issue #328 *); + trait = _ (* TODO: see issue #328 *); bounds_impls = _; } when Concrete_ident.eq_name Core__ops__index__IndexMut__index_mut meth -> @@ -207,7 +208,7 @@ let resugar_index_mut (e : expr) : (expr * expr) option = f = { e = GlobalVar (`Concrete meth); _ }; args = [ x; index ]; generic_args = _ (* TODO: see issue #328 *); - impl = _ (* TODO: see issue #328 *); + trait = _ (* TODO: see issue #328 *); bounds_impls = _; } when Concrete_ident.eq_name Core__ops__index__Index__index meth -> @@ -225,10 +226,11 @@ module type EXPR = sig val c_generic_value : Thir.span -> Thir.generic_arg -> generic_value val c_generics : Thir.generics -> generics val c_param : Thir.span -> Thir.param -> param + val c_fn_params : Thir.span -> Thir.param list -> param list val c_trait_item' : Thir.trait_item -> Thir.trait_item_kind -> trait_item' val c_trait_ref : Thir.span -> Thir.trait_ref -> trait_goal val c_impl_expr : Thir.span -> Thir.impl_expr -> impl_expr - val c_clause : Thir.span -> Thir.clause -> impl_ident option + val c_clause : Thir.span -> Thir.clause -> generic_constraint option end (* BinOp to [core::ops::*] overloaded functions *) @@ -256,6 +258,12 @@ end) : EXPR = struct | Ge -> Core__cmp__PartialOrd__ge | Gt -> Core__cmp__PartialOrd__gt | Eq -> Core__cmp__PartialEq__eq + | AddWithOverflow | SubWithOverflow | MulWithOverflow -> + assertion_failure (Span.to_thir span) + "Overflowing binary operators are not suppored" + | Cmp -> + assertion_failure (Span.to_thir span) + "`Cmp` binary operator is not suppored" | Offset -> Core__ptr__const_ptr__Impl__offset in let primitive_names_of_binop : Thir.bin_op -> Concrete_ident.name = function @@ -275,6 +283,12 @@ end) : EXPR = struct | Ge -> Rust_primitives__u128__ge | Gt -> Rust_primitives__u128__gt | Eq -> Rust_primitives__u128__eq + | AddWithOverflow | SubWithOverflow | MulWithOverflow -> + assertion_failure (Span.to_thir span) + "Overflowing binary operators are not suppored" + | Cmp -> + assertion_failure (Span.to_thir span) + "`Cmp` binary operator is not suppored" | Offset -> Rust_primitives__offset in let name = @@ -313,8 +327,10 @@ end) : EXPR = struct let name = primitive_names_of_binop op in let expected, f = match op with - | Add | Sub | Mul | Div -> both int <|> both float - | Rem -> both int + | Add | Sub | Mul | AddWithOverflow | SubWithOverflow + | MulWithOverflow | Div -> + both int <|> both float + | Rem | Cmp -> both int | BitXor | BitAnd | BitOr -> both int <|> both bool | Shl | Shr -> int <*> int | Lt | Le | Ne | Ge | Gt -> both int <|> both float @@ -355,6 +371,75 @@ end) : EXPR = struct let v = Global_ident.of_name Value Rust_primitives__hax__dropped_body in { span; typ; e = GlobalVar v } + and c_block ~expr ~span ~stmts ~ty : expr = + let full_span = Span.of_thir span in + let typ = c_ty span ty in + (* if there is no expression & the last expression is ⊥, just use that *) + let lift_last_statement_as_expr_if_possible expr stmts (ty : Thir.ty) = + match (ty, expr, List.drop_last stmts, List.last stmts) with + | ( Thir.Never, + None, + Some stmts, + Some ({ kind = Thir.Expr { expr; _ }; _ } : Thir.stmt) ) -> + (stmts, Some expr) + | _ -> (stmts, expr) + in + let o_stmts, o_expr = + lift_last_statement_as_expr_if_possible expr stmts ty + in + let init = + Option.map + ~f:(fun e -> + let e = c_expr e in + { e with e = Block (e, W.block) }) + o_expr + |> Option.value ~default:(unit_expr full_span) + in + List.fold_right o_stmts ~init ~f:(fun { kind; _ } body -> + match kind with + | Expr { expr = rhs; _ } -> + let rhs = c_expr rhs in + let e = + Let { monadic = None; lhs = wild_pat rhs.span rhs.typ; rhs; body } + in + { e; typ; span = Span.union rhs.span body.span } + | Let + { + else_block = Some { expr; span; stmts; _ }; + pattern = lhs; + initializer' = Some rhs; + _; + } -> + let lhs = c_pat lhs in + let rhs = c_expr rhs in + let else_block = c_block ~expr ~span ~stmts ~ty in + let lhs_body_span = Span.union lhs.span body.span in + let e = + Match + { + arms = + [ + U.make_arm lhs body lhs_body_span; + U.make_arm + { p = PWild; span = else_block.span; typ = lhs.typ } + { else_block with typ = body.typ } + else_block.span; + ]; + scrutinee = rhs; + } + in + { e; typ; span = full_span } + | Let { initializer' = None; _ } -> + unimplemented ~issue_id:156 [ span ] + "Sorry, Hax does not support declare-first let bindings (see \ + https://doc.rust-lang.org/rust-by-example/variable_bindings/declare.html) \ + for now." + | Let { pattern = lhs; initializer' = Some rhs; _ } -> + let lhs = c_pat lhs in + let rhs = c_expr rhs in + let e = Let { monadic = None; lhs; rhs; body } in + { e; typ; span = Span.union rhs.span body.span }) + and c_expr_unwrapped (e : Thir.decorated_for__expr_kind) : expr = (* TODO: eliminate that `call`, use the one from `ast_utils` *) let call f args = @@ -363,7 +448,7 @@ end) : EXPR = struct f; args = List.map ~f:c_expr args; generic_args = []; - impl = None; + trait = None; bounds_impls = []; } in @@ -394,12 +479,10 @@ end) : EXPR = struct Option.value ~default:(U.unit_expr span) @@ Option.map ~f:c_expr else_opt in - let arm_then = - { arm = { arm_pat; body = then_ }; span = then_.span } - in + let arm_then = U.make_arm arm_pat then_ then_.span in let arm_else = let arm_pat = { arm_pat with p = PWild } in - { arm = { arm_pat; body = else_ }; span = else_.span } + U.make_arm arm_pat else_ else_.span in Match { scrutinee; arms = [ arm_then; arm_else ] } | If { cond; else_opt; then'; _ } -> @@ -411,7 +494,7 @@ end) : EXPR = struct { args; fn_span = _; - impl; + trait; from_hir_call = _; fun'; ty = _; @@ -420,12 +503,11 @@ end) : EXPR = struct } -> let args = List.map ~f:c_expr args in let bounds_impls = List.map ~f:(c_impl_expr e.span) bounds_impls in - let generic_args = - List.map ~f:(c_generic_value e.span) generic_args - in + let c_generic_values = List.map ~f:(c_generic_value e.span) in + let generic_args = c_generic_values generic_args in let f = let f = c_expr fun' in - match (impl, fun'.contents) with + match (trait, fun'.contents) with | Some _, GlobalName { id } -> { f with e = GlobalVar (def_id (AssociatedItem Value) id) } | _ -> f @@ -437,7 +519,8 @@ end) : EXPR = struct args; generic_args; bounds_impls; - impl = Option.map ~f:(c_impl_expr e.span) impl; + trait = + Option.map ~f:(c_impl_expr e.span *** c_generic_values) trait; } | Box { value } -> (U.call Rust_primitives__hax__box_new [ c_expr value ] span typ).e @@ -457,7 +540,10 @@ end) : EXPR = struct (U.call (match op with | Not -> Core__ops__bit__Not__not - | Neg -> Core__ops__arith__Neg__neg) + | Neg -> Core__ops__arith__Neg__neg + | PtrMetadata -> + assertion_failure (Span.to_thir span) + "Unsupported unary operator: `PtrMetadata`") [ c_expr arg ] span typ) .e @@ -498,61 +584,8 @@ end) : EXPR = struct | Let _ -> unimplemented [ e.span ] "Let" | Block { safety_mode = BuiltinUnsafe | ExplicitUnsafe; _ } -> unsafe_block [ e.span ] - | Block o -> - (* if there is no expression & the last expression is ⊥, just use that *) - let lift_last_statement_as_expr_if_possible expr stmts (ty : Thir.ty) - = - match (ty, expr, List.drop_last stmts, List.last stmts) with - | ( Thir.Never, - None, - Some stmts, - Some ({ kind = Thir.Expr { expr; _ }; _ } : Thir.stmt) ) -> - (stmts, Some expr) - | _ -> (stmts, expr) - in - let o_stmts, o_expr = - lift_last_statement_as_expr_if_possible o.expr o.stmts e.ty - in - let init = - Option.map - ~f:(fun e -> - let e = c_expr e in - { e with e = Block (e, W.block) }) - o_expr - |> Option.value ~default:(unit_expr span) - in - let { e; _ } = - List.fold_right o_stmts ~init ~f:(fun { kind; _ } body -> - match kind with - | Expr { expr = rhs; _ } -> - let rhs = c_expr rhs in - let e = - Let - { - monadic = None; - lhs = wild_pat rhs.span rhs.typ; - rhs; - body; - } - in - { e; typ; span = Span.union rhs.span body.span } - | Let { else_block = Some _; _ } -> - unimplemented ~issue_id:155 [ e.span ] - "Sorry, Hax does not support [let-else] (see \ - https://doc.rust-lang.org/rust-by-example/flow_control/let_else.html) \ - for now." - | Let { initializer' = None; _ } -> - unimplemented ~issue_id:156 [ e.span ] - "Sorry, Hax does not support declare-first let bindings \ - (see \ - https://doc.rust-lang.org/rust-by-example/variable_bindings/declare.html) \ - for now." - | Let { pattern = lhs; initializer' = Some rhs; _ } -> - let lhs = c_pat lhs in - let rhs = c_expr rhs in - let e = Let { monadic = None; lhs; rhs; body } in - { e; typ; span = Span.union rhs.span body.span }) - in + | Block { expr; span; stmts; _ } -> + let { e; _ } = c_block ~expr ~span ~stmts ~ty:e.ty in e | Assign { lhs; rhs } -> let lhs = c_expr lhs in @@ -574,7 +607,7 @@ end) : EXPR = struct f = { e = projector; typ = TArrow ([ lhs.typ ], typ); span }; args = [ lhs ]; generic_args = [] (* TODO: see issue #328 *); - impl = None (* TODO: see issue #328 *); + trait = None (* TODO: see issue #328 *); bounds_impls = []; } | TupleField { lhs; field } -> @@ -591,7 +624,7 @@ end) : EXPR = struct f = { e = projector; typ = TArrow ([ lhs.typ ], typ); span }; args = [ lhs ]; generic_args = [] (* TODO: see issue #328 *); - impl = None (* TODO: see issue #328 *); + trait = None (* TODO: see issue #328 *); bounds_impls = []; } | GlobalName { id } -> GlobalVar (def_id Value id) @@ -727,7 +760,7 @@ end) : EXPR = struct }; args = [ e ]; generic_args = _; - impl = _; + trait = _; bounds_impls = _; (* TODO: see issue #328 *) } -> @@ -800,13 +833,13 @@ end) : EXPR = struct let typ, typ_span = c_canonical_user_type_annotation annotation in let pat = c_pat subpattern in PAscription { typ; typ_span; pat } - | Binding { mode; mutability; subpattern; ty; var; _ } -> - let mut = c_mutability W.mutable_variable mutability in + | Binding { mode; subpattern; ty; var; _ } -> + let mut = c_mutability W.mutable_variable mode.mutability in let subpat = Option.map ~f:(c_pat &&& Fn.const W.as_pattern) subpattern in let typ = c_ty pat.span ty in - let mode = c_binding_mode pat.span mode in + let mode = c_binding_mode mode.by_ref in let var = local_ident Expr var in PBinding { mut; mode; var; typ; subpat } | Variant { info; subpatterns; _ } -> @@ -839,10 +872,14 @@ end) : EXPR = struct ("expected a pattern, got " ^ [%show: expr'] e) in (c_constant_expr value |> pat_of_expr).p + | InlineConstant { subpattern; _ } -> (c_pat subpattern).p | Array _ -> unimplemented [ pat.span ] "Pat:Array" | Or { pats } -> POr { subpats = List.map ~f:c_pat pats } | Slice _ -> unimplemented [ pat.span ] "pat Slice" | Range _ -> unimplemented [ pat.span ] "pat Range" + | DerefPattern _ -> unimplemented [ pat.span ] "pat DerefPattern" + | Never -> unimplemented [ pat.span ] "pat Never" + | Error _ -> unimplemented [ pat.span ] "pat Error" in { p = v; span; typ } @@ -878,7 +915,7 @@ end) : EXPR = struct and c_pointer e typ span cast source = match cast with - | ClosureFnPointer Normal | ReifyFnPointer -> + | ClosureFnPointer Safe | ReifyFnPointer -> (* we have arrow types, we do not distinguish between top-level functions and closures *) (c_expr source).e | Unsize -> @@ -915,7 +952,9 @@ end) : EXPR = struct | Char -> TChar | Int k -> TInt (c_int_ty k) | Uint k -> TInt (c_uint_ty k) - | Float k -> TFloat (match k with F32 -> F32 | F64 -> F64) + | Float k -> + TFloat + (match k with F16 -> F16 | F32 -> F32 | F64 -> F64 | F128 -> F128) | Arrow value -> let ({ inputs; output; _ } : Thir.ty_fn_sig) = value.value in let inputs = @@ -956,8 +995,27 @@ end) : EXPR = struct (* TODO: [id] might not unique *) TParam { name; id = Local_ident.mk_id Typ (MyInt64.to_int_exn index) } | Error -> unimplemented [ span ] "type Error" - | Dynamic _ -> unimplemented [ span ] "type Dynamic" - | Generator _ -> unimplemented [ span ] "type Generator" + | Dynamic (predicates, _region, Dyn) -> ( + let goals, non_traits = + List.partition_map + ~f:(fun pred -> + match pred.value with + | Trait { args; def_id } -> + let goal : dyn_trait_goal = + { + trait = Concrete_ident.of_def_id Trait def_id; + non_self_args = List.map ~f:(c_generic_value span) args; + } + in + First goal + | _ -> Second ()) + predicates + in + match non_traits with + | [] -> TDyn { witness = W.dyn; goals } + | _ -> unimplemented [ span ] "type Dyn with non trait predicate") + | Dynamic (_, _, DynStar) -> unimplemented [ span ] "type DynStar" + | Coroutine _ -> unimplemented [ span ] "type Coroutine" | Placeholder _ -> unimplemented [ span ] "type Placeholder" | Bound _ -> unimplemented [ span ] "type Bound" | Infer _ -> unimplemented [ span ] "type Infer" @@ -1023,7 +1081,31 @@ end) : EXPR = struct let arm_pat = c_pat arm.pattern in let body = c_expr arm.body in let span = Span.of_thir arm.span in - { arm = { arm_pat; body }; span } + let guard = + Option.map + ~f:(fun (e : Thir.decorated_for__expr_kind) -> + let guard = + match e.contents with + | Let { expr; pat } -> + IfLet + { + lhs = c_pat pat; + rhs = c_expr expr; + witness = W.match_guard; + } + | _ -> + IfLet + { + lhs = + { p = PConstant { lit = Bool true }; span; typ = TBool }; + rhs = c_expr e; + witness = W.match_guard; + } + in + { guard; span = Span.of_thir e.span }) + arm.guard + in + { arm = { arm_pat; body; guard }; span } and c_param span (param : Thir.param) : param = { @@ -1033,6 +1115,10 @@ end) : EXPR = struct attrs = c_attrs param.attributes; } + let c_fn_params span (params : Thir.param list) : param list = + if List.is_empty params then [ U.make_unit_param (Span.of_thir span) ] + else List.map ~f:(c_param span) params + let c_generic_param (param : Thir.generic_param) : generic_param = let ident = let kind = @@ -1062,15 +1148,23 @@ end) : EXPR = struct let attrs = c_attrs param.attributes in { ident; span; attrs; kind } - let c_clause_kind span id (kind : Thir.clause_kind) : impl_ident option = + let c_clause_kind span id (kind : Thir.clause_kind) : + generic_constraint option = match kind with | Trait { is_positive = true; trait_ref } -> let args = List.map ~f:(c_generic_value span) trait_ref.generic_args in let trait = Concrete_ident.of_def_id Trait trait_ref.def_id in - Some { goal = { trait; args }; name = id } + Some (GCType { goal = { trait; args }; name = id }) + | Projection { impl_expr; assoc_item; ty } -> + let impl = c_impl_expr span impl_expr in + let assoc_item = + Concrete_ident.of_def_id (AssociatedItem Type) assoc_item.def_id + in + let typ = c_ty span ty in + Some (GCProjection { impl; assoc_item; typ }) | _ -> None - let c_clause span (p : Thir.clause) : impl_ident option = + let c_clause span (p : Thir.clause) : generic_constraint option = let ({ kind; id } : Thir.clause) = p in c_clause_kind span id kind.value @@ -1085,10 +1179,7 @@ end) : EXPR = struct aux [] let c_generics (generics : Thir.generics) : generics = - let bounds = - List.filter_map ~f:(c_clause generics.span) generics.bounds - |> List.map ~f:(fun impl_ident -> GCType impl_ident) - in + let bounds = List.filter_map ~f:(c_clause generics.span) generics.bounds in { params = List.map ~f:c_generic_param generics.params; constraints = bounds |> list_dedup equal_generic_constraint; @@ -1098,11 +1189,11 @@ end) : EXPR = struct trait_item' = let span = super.span in match item with - | Const (_, Some _) -> - unimplemented [ span ] - "TODO: traits: no support for defaults in traits for now" + | Const (_, Some default) -> + TIDefault + { params = []; body = c_expr default; witness = W.trait_item_default } | Const (ty, None) -> TIFn (c_ty span ty) - | ProvidedFn (sg, _) | RequiredFn (sg, _) -> + | RequiredFn (sg, _) -> let (Thir.{ inputs; output; _ } : Thir.fn_decl) = sg.decl in let output = match output with @@ -1114,8 +1205,19 @@ end) : EXPR = struct else List.map ~f:(c_ty span) inputs in TIFn (TArrow (inputs, output)) + | ProvidedFn (_, { params; body; _ }) -> + TIDefault + { + params = c_fn_params span params; + body = c_expr body; + witness = W.trait_item_default; + } | Type (bounds, None) -> - let bounds = List.filter_map ~f:(c_clause span) bounds in + let bounds = + List.filter_map ~f:(c_clause span) bounds + |> List.filter_map ~f:(fun bound -> + match bound with GCType impl -> Some impl | _ -> None) + in TIType bounds | Type (_, Some _) -> unimplemented [ span ] @@ -1132,7 +1234,8 @@ include struct let import_trait_ref : Types.span -> Types.trait_ref -> Ast.Rust.trait_goal = c_trait_ref - let import_clause : Types.span -> Types.clause -> Ast.Rust.impl_ident option = + let import_clause : + Types.span -> Types.clause -> Ast.Rust.generic_constraint option = c_clause end @@ -1249,7 +1352,8 @@ let cast_of_enum typ_name generics typ thir_span in (Exp e, (pat, acc))) |> List.map ~f:(Fn.id *** function Exp e -> e | Lit n -> to_expr n) - |> List.map ~f:(fun (arm_pat, body) -> { arm = { arm_pat; body }; span }) + |> List.map ~f:(fun (arm_pat, body) -> + { arm = { arm_pat; body; guard = None }; span }) in let scrutinee_var = Local_ident.{ name = "x"; id = Local_ident.mk_id Expr (-1) } @@ -1321,10 +1425,6 @@ and c_item_unwrapped ~ident ~drop_body (item : Thir.item) : item list = ty = c_ty item.span ty; } | Fn (generics, { body; params; _ }) -> - let params = - if List.is_empty params then [ U.make_unit_param span ] - else List.map ~f:(c_param item.span) params - in mk @@ Fn { @@ -1332,7 +1432,7 @@ and c_item_unwrapped ~ident ~drop_body (item : Thir.item) : item list = Concrete_ident.of_def_id Value (Option.value_exn item.def_id); generics = c_generics generics; body = c_body body; - params; + params = c_fn_params item.span params; } | Enum (variants, generics, repr) -> let def_id = Option.value_exn item.def_id in @@ -1357,7 +1457,7 @@ and c_item_unwrapped ~ident ~drop_body (item : Thir.item) : item list = List.for_all ~f:(fun { data; _ } -> match data with - | Unit _ | Tuple ([], _, _) | Struct ([], _) -> true + | Unit _ | Tuple ([], _, _) | Struct { fields = []; _ } -> true | _ -> false) variants in @@ -1365,11 +1465,13 @@ and c_item_unwrapped ~ident ~drop_body (item : Thir.item) : item list = List.map ~f: (fun ({ data; def_id = variant_id; attributes; _ } as original) -> - let is_record = [%matches? Types.Struct (_ :: _, _)] data in + let is_record = + [%matches? Types.Struct { fields = _ :: _; _ }] data + in let name = Concrete_ident.of_def_id kind variant_id in let arguments = match data with - | Tuple (fields, _, _) | Struct (fields, _) -> + | Tuple (fields, _, _) | Struct { fields; _ } -> List.map ~f:(fun { def_id = id; ty; span; attributes; _ } -> ( Concrete_ident.of_def_id Field id, @@ -1413,7 +1515,7 @@ and c_item_unwrapped ~ident ~drop_body (item : Thir.item) : item list = in match v with | Tuple (fields, _, _) -> mk fields false - | Struct ((_ :: _ as fields), _) -> mk fields true + | Struct { fields = _ :: _ as fields; _ } -> mk fields true | _ -> { name; arguments = []; is_record = false; attrs } in let variants = [ v ] in @@ -1428,7 +1530,7 @@ and c_item_unwrapped ~ident ~drop_body (item : Thir.item) : item list = span = Span.of_thir span; witness = W.macro; } - | Trait (No, Normal, generics, _bounds, items) -> + | Trait (No, Safe, generics, _bounds, items) -> let items = List.filter ~f:(fun { attributes; _ } -> not (should_skip attributes)) @@ -1495,14 +1597,14 @@ and c_item_unwrapped ~ident ~drop_body (item : Thir.item) : item list = let attrs = c_item_attrs item.attributes in { span = Span.of_thir item.span; v; ident; attrs }) items - | Impl { unsafety = Unsafe; _ } -> unsafe_block [ item.span ] + | Impl { safety = Unsafe; _ } -> unsafe_block [ item.span ] | Impl { of_trait = Some of_trait; generics; self_ty; items; - unsafety = Normal; + safety = Safe; parent_bounds; _; } -> @@ -1551,9 +1653,13 @@ and c_item_unwrapped ~ident ~drop_body (item : Thir.item) : item list = parent_bounds = List.filter_map ~f:(fun (clause, impl_expr, span) -> - let* trait_goal = c_clause span clause in - Some - (c_impl_expr span impl_expr, trait_goal)) + let* bound = c_clause span clause in + match bound with + | GCType trait_goal -> + Some + ( c_impl_expr span impl_expr, + trait_goal ) + | _ -> None) parent_bounds; }); ii_ident; @@ -1563,8 +1669,11 @@ and c_item_unwrapped ~ident ~drop_body (item : Thir.item) : item list = parent_bounds = List.filter_map ~f:(fun (clause, impl_expr, span) -> - let* trait_goal = c_clause span clause in - Some (c_impl_expr span impl_expr, trait_goal)) + let* bound = c_clause span clause in + match bound with + | GCType trait_goal -> + Some (c_impl_expr span impl_expr, trait_goal) + | _ -> None) parent_bounds; } | Use ({ span = _; res; segments; rename }, _) -> diff --git a/engine/lib/import_thir.mli b/engine/lib/import_thir.mli index 2d0374a63..70bff0423 100644 --- a/engine/lib/import_thir.mli +++ b/engine/lib/import_thir.mli @@ -1,6 +1,8 @@ val import_ty : Types.span -> Types.ty -> Ast.Rust.ty val import_trait_ref : Types.span -> Types.trait_ref -> Ast.Rust.trait_goal -val import_clause : Types.span -> Types.clause -> Ast.Rust.impl_ident option + +val import_clause : + Types.span -> Types.clause -> Ast.Rust.generic_constraint option val import_item : drop_body:bool -> diff --git a/engine/lib/phases/phase_and_mut_defsite.ml b/engine/lib/phases/phase_and_mut_defsite.ml index 25583e2f1..8a43df7ee 100644 --- a/engine/lib/phases/phase_and_mut_defsite.ml +++ b/engine/lib/phases/phase_and_mut_defsite.ml @@ -286,6 +286,10 @@ struct let output = body.typ in let ty = B.TArrow (inputs, output) in Some (B.TIFn ty) + | TIDefault { params; body; witness } -> + let* params, body = rewrite_function params body in + let witness = S.trait_item_default span witness in + Some (B.TIDefault { params; body; witness }) | _ -> None) |> Option.value_or_thunk ~default:(Fn.flip super#visit_trait_item' item.ti_v) diff --git a/engine/lib/phases/phase_cf_into_monads.ml b/engine/lib/phases/phase_cf_into_monads.ml index 373c31f50..86f64560d 100644 --- a/engine/lib/phases/phase_cf_into_monads.ml +++ b/engine/lib/phases/phase_cf_into_monads.ml @@ -163,10 +163,11 @@ struct | Match { scrutinee; arms } -> let arms = List.map - ~f:(fun { arm = { arm_pat; body = a }; span } -> + ~f:(fun { arm = { arm_pat; body = a; guard }; span } -> let b = dexpr a in let m = KnownMonads.from_typ dty a.typ b.typ in - (m, (dpat arm_pat, span, b))) + let g = Option.map ~f:dguard guard in + (m, (dpat arm_pat, span, b, g))) arms in let arms = @@ -177,10 +178,10 @@ struct |> List.reduce_exn ~f:(KnownMonads.lub span) in List.map - ~f:(fun (mself, (arm_pat, span, body)) -> + ~f:(fun (mself, (arm_pat, span, body, guard)) -> let body = KnownMonads.lift "Match" body mself.monad m in let arm_pat = { arm_pat with typ = body.typ } in - ({ arm = { arm_pat; body }; span } : B.arm)) + ({ arm = { arm_pat; body; guard }; span } : B.arm)) arms in let typ = diff --git a/engine/lib/phases/phase_direct_and_mut.ml b/engine/lib/phases/phase_direct_and_mut.ml index 1348c711a..03af8bb3e 100644 --- a/engine/lib/phases/phase_direct_and_mut.ml +++ b/engine/lib/phases/phase_direct_and_mut.ml @@ -101,7 +101,8 @@ struct and translate_app (span : span) (otype : A.ty) (f : A.expr) (raw_args : A.expr list) (generic_args : B.generic_value list) - (impl : B.impl_expr option) bounds_impls : B.expr = + (trait : (B.impl_expr * B.generic_value list) option) bounds_impls : + B.expr = (* `otype` and `_otype` (below) are supposed to be the same type, but sometimes `_otype` is less precise (i.e. an associated type while a concrete type is available) *) @@ -140,7 +141,7 @@ struct let args = List.map ~f:dexpr raw_args in B. { - e = B.App { f; args; generic_args; impl; bounds_impls }; + e = B.App { f; args; generic_args; trait; bounds_impls }; typ; span; } @@ -219,7 +220,8 @@ struct B. { e = - App { f; args = unmut_args; generic_args; impl; bounds_impls }; + App + { f; args = unmut_args; generic_args; trait; bounds_impls }; typ = pat.typ; span = pat.span; } @@ -269,11 +271,12 @@ struct and dexpr_unwrapped (expr : A.expr) : B.expr = let span = expr.span in match expr.e with - | App { f; args; generic_args; impl; bounds_impls } -> - let generic_args = List.map ~f:(dgeneric_value span) generic_args in - let impl = Option.map ~f:(dimpl_expr span) impl in + | App { f; args; generic_args; trait; bounds_impls } -> + let dgeneric_args = List.map ~f:(dgeneric_value span) in + let generic_args = dgeneric_args generic_args in + let trait = Option.map ~f:(dimpl_expr span *** dgeneric_args) trait in let bounds_impls = List.map ~f:(dimpl_expr span) bounds_impls in - translate_app span expr.typ f args generic_args impl bounds_impls + translate_app span expr.typ f args generic_args trait bounds_impls | _ -> let e = dexpr' span expr.e in B.{ e; typ = dty expr.span expr.typ; span = expr.span } diff --git a/engine/lib/phases/phase_drop_match_guards.ml b/engine/lib/phases/phase_drop_match_guards.ml new file mode 100644 index 000000000..4f50ff5a6 --- /dev/null +++ b/engine/lib/phases/phase_drop_match_guards.ml @@ -0,0 +1,248 @@ +(* This phase removes guards from pattern matchings. It rewrites + them using only pattern matchings without guards. + See #806 and the example in tests/guards. *) + +(* Rewrite example: *) +(* + match x { + None => 0, + Some(v) if let Ok(y) = v => y, + Some(Err(y)) => y, + _ => 1, + } +*) +(* Becomes *) +(* + match x { + None => 0, + _ => match match x { + Some(v) => match v { + Ok(y) => Some(y), + _ => None, + }, + _ => None, + } { + Some(y) => y, + None => match x { + Some(Err(y)) => y, + _ => 1, + }, + }, + } +*) + +open! Prelude + +module%inlined_contents Make (F : Features.T) = struct + open Ast + module FA = F + + module FB = struct + include F + include Features.Off.Match_guard + end + + include + Phase_utils.MakeBase (F) (FB) + (struct + let phase_id = Diagnostics.Phase.DropMatchGuards + end) + + module UA = Ast_utils.Make (F) + module UB = Ast_utils.Make (FB) + + module Implem : ImplemT.T = struct + let metadata = metadata + + module S = struct + include Features.SUBTYPE.Id + end + + [%%inline_defs dmutability] + + let maybe_simplified_match scrutinee ?(original_arms : A.arm list = []) + (arms : B.arm list) : B.expr' = + match (original_arms, arms) with + (* If the one wildcard branch was not produced by this phase, keep it *) + | ( [ { arm = { arm_pat = { p = PWild; _ }; _ }; _ } ], + [ { arm = { arm_pat = { p = PWild; _ }; _ }; _ } ] ) -> + Match { scrutinee; arms } + (* If there is only one wildcard branch we can simplify *) + | _, [ { arm = { body; arm_pat = { p = PWild; _ }; _ }; _ } ] -> body.e + (* General case *) + | _ -> Match { scrutinee; arms } + + let rec dexpr' (span : span) (expr : A.expr') : B.expr' = + match expr with + | [%inline_arms "dexpr'.*" - Match] -> auto + | Match { scrutinee; arms } -> + let new_arms = transform_arms (dexpr scrutinee) (List.rev arms) [] in + maybe_simplified_match ~original_arms:arms (dexpr scrutinee) new_arms + + and transform_arms (scrutinee : B.expr) (remaining : A.arm list) + (treated : B.arm list) : B.arm list = + match remaining with + | [] -> treated + | { arm = { arm_pat; body; guard = None }; span } :: remaining -> + let new_arm : B.arm = UB.make_arm (dpat arm_pat) (dexpr body) span in + transform_arms scrutinee remaining (new_arm :: treated) + (* Matches an arm `arm_pat if let lhs = rhs => body` *) + (* And rewrites to `_ => match {Some(x) => x, None => match scrutinee {} }` *) + (* where `option_match` is `match scrutinee {arm_pat => , _ => None }` *) + (* and `match_guard` is `match rhs {lhs => Some(body), _ => None}` *) + (* and `treated` is the other arms coming after this one (that have already been treated as the arms are reversed ) *) + | { + arm = + { + arm_pat; + body; + guard = Some { guard = IfLet { lhs; rhs; _ }; span = guard_span }; + }; + span; + } + :: remaining -> + let result_typ = dty span body.typ in + let opt_result_typ : B.ty = + TApp + { + ident = Global_ident.of_name Type Core__option__Option; + args = [ GType result_typ ]; + } + in + let mk_opt_expr (value : B.expr option) : B.expr = + let (name : Concrete_ident.name), args = + match value with + | Some v -> (Core__option__Option__Some, [ v ]) + | None -> (Core__option__Option__None, []) + in + UB.call_Constructor name false args guard_span opt_result_typ + in + + let mk_opt_pattern (binding : B.pat option) : B.pat = + let (name : Concrete_ident.name), (args : B.field_pat list) = + match binding with + | Some b -> + ( Core__option__Option__Some, + [ { field = `TupleField (0, 1); pat = b } ] ) + | None -> (Core__option__Option__None, []) + in + { + p = + PConstruct + { + name = + Global_ident.of_name + (Constructor { is_struct = false }) + name; + args; + is_record = false; + is_struct = false; + }; + span = guard_span; + typ = opt_result_typ; + } + in + + let expr_none = mk_opt_expr None in + + (* This is the nested pattern matching equivalent to the guard *) + (* Example: .. if let pat = rhs => body *) + (* Rewrites with match rhs { pat => Some(body), _ => None }*) + let guard_match : B.expr' = + Match + { + scrutinee = dexpr rhs; + arms = + [ + UB.make_arm (dpat lhs) + (mk_opt_expr (Some (dexpr body))) + span; + UB.make_arm + (UB.make_wild_pat (dty guard_span lhs.typ) guard_span) + expr_none guard_span; + ]; + } + in + + (* `r` corresponds to `option_match` in the example above *) + let r : B.expr = + { + e = + Match + { + scrutinee; + arms = + [ + UB.make_arm (dpat arm_pat) + { + e = guard_match; + span = guard_span; + typ = opt_result_typ; + } + guard_span; + UB.make_arm + (UB.make_wild_pat + (dty guard_span arm_pat.typ) + guard_span) + expr_none guard_span; + ]; + }; + span = guard_span; + typ = opt_result_typ; + } + in + let id = UB.fresh_local_ident_in [] "x" in + let new_body : B.expr = + { + e = + Match + { + scrutinee = r; + arms = + [ + UB.make_arm + (mk_opt_pattern + (Some + { + p = + PBinding + { + mut = Immutable; + mode = ByValue; + var = id; + typ = result_typ; + subpat = None; + }; + span; + typ = result_typ; + })) + { e = LocalVar id; span; typ = result_typ } + guard_span; + UB.make_arm (mk_opt_pattern None) + { + e = maybe_simplified_match scrutinee treated; + span = guard_span; + typ = result_typ; + } + guard_span; + ]; + }; + span = guard_span; + typ = result_typ; + } + in + let new_arm : B.arm = + UB.make_arm + (UB.make_wild_pat (dty span arm_pat.typ) span) + new_body span + in + transform_arms scrutinee remaining [ new_arm ] + [@@inline_ands + bindings_of dexpr - dexpr' - darm - darm' - dguard - dguard'] + + [%%inline_defs "Item.*"] + end + + include Implem +end +[@@add "subtype.ml"] diff --git a/engine/lib/phases/phase_drop_match_guards.mli b/engine/lib/phases/phase_drop_match_guards.mli new file mode 100644 index 000000000..50d0d8864 --- /dev/null +++ b/engine/lib/phases/phase_drop_match_guards.mli @@ -0,0 +1,18 @@ +open! Prelude + +module Make (F : Features.T) : sig + include module type of struct + module FA = F + + module FB = struct + include F + include Features.Off.Match_guard + end + + module A = Ast.Make (F) + module B = Ast.Make (FB) + module ImplemT = Phase_utils.MakePhaseImplemT (A) (B) + end + + include ImplemT.T +end diff --git a/engine/lib/phases/phase_drop_references.ml b/engine/lib/phases/phase_drop_references.ml index 8bdd29ff2..06835f428 100644 --- a/engine/lib/phases/phase_drop_references.ml +++ b/engine/lib/phases/phase_drop_references.ml @@ -51,6 +51,13 @@ struct args = List.filter_map ~f:(dgeneric_value span) r.args; } + and ddyn_trait_goal (span : span) (r : A.dyn_trait_goal) : B.dyn_trait_goal + = + { + trait = r.trait; + non_self_args = List.filter_map ~f:(dgeneric_value span) r.non_self_args; + } + and dpat' (span : span) (p : A.pat') : B.pat' = match p with | [%inline_arms "dpat'.*" - PBinding - PDeref] -> auto @@ -111,15 +118,14 @@ struct body = dexpr body; captures = List.map ~f:dexpr captures; } - | App { f; args; generic_args; impl; bounds_impls } -> + | App { f; args; generic_args; trait; bounds_impls } -> let f = dexpr f in let args = List.map ~f:dexpr args in - let impl = Option.map ~f:(dimpl_expr span) impl in - let generic_args = - List.filter_map ~f:(dgeneric_value span) generic_args - in + let dgeneric_args = List.filter_map ~f:(dgeneric_value span) in + let trait = Option.map ~f:(dimpl_expr span *** dgeneric_args) trait in + let generic_args = dgeneric_args generic_args in let bounds_impls = List.map ~f:(dimpl_expr span) bounds_impls in - App { f; args; generic_args; impl; bounds_impls } + App { f; args; generic_args; trait; bounds_impls } | _ -> . [@@inline_ands bindings_of dexpr - dbinding_mode] @@ -136,11 +142,21 @@ struct in Some B.{ ident; kind; attrs; span } + and dprojection_predicate (span : span) (r : A.projection_predicate) : + B.projection_predicate = + { + impl = dimpl_expr span r.impl; + assoc_item = r.assoc_item; + typ = dty span r.typ; + } + let dgeneric_constraint (span : span) (p : A.generic_constraint) : B.generic_constraint option = match p with | GCLifetime _ -> None | GCType idents -> Some (B.GCType (dimpl_ident span idents)) + | GCProjection projection -> + Some (B.GCProjection (dprojection_predicate span projection)) let dgenerics (span : span) (g : A.generics) : B.generics = { diff --git a/engine/lib/phases/phase_functionalize_loops.ml b/engine/lib/phases/phase_functionalize_loops.ml index 1e29f7959..07b010714 100644 --- a/engine/lib/phases/phase_functionalize_loops.ml +++ b/engine/lib/phases/phase_functionalize_loops.ml @@ -33,6 +33,127 @@ struct include Features.SUBTYPE.Id end + type body_and_invariant = { + body : B.expr; + invariant : (B.pat * B.expr) option; + } + + let extract_loop_invariant (body : B.expr) : body_and_invariant = + match body.e with + | Let + { + monadic = None; + lhs = { p = PWild; _ }; + rhs = + { + e = + App + { + f = { e = GlobalVar f; _ }; + args = + [ + { + e = + Closure { params = [ pat ]; body = invariant; _ }; + _; + }; + ]; + _; + }; + _; + }; + body; + } + when Global_ident.eq_name Hax_lib___internal_loop_invariant f -> + { body; invariant = Some (pat, invariant) } + | _ -> { body; invariant = None } + + type iterator = + | Range of { start : B.expr; end_ : B.expr } + | Slice of B.expr + | ChunksExact of { size : B.expr; slice : B.expr } + | Enumerate of iterator + | StepBy of { n : B.expr; it : iterator } + [@@deriving show] + + let rec as_iterator' (e : B.expr) : iterator option = + match e.e with + | Construct + { + constructor = `Concrete range_ctor; + is_record = true; + is_struct = true; + fields = + [ (`Concrete start_field, start); (`Concrete end_field, end_) ]; + base = None; + } + when Concrete_ident.eq_name Core__ops__range__Range__start start_field + && Concrete_ident.eq_name Core__ops__range__Range range_ctor + && Concrete_ident.eq_name Core__ops__range__Range__end end_field -> + Some (Range { start; end_ }) + | _ -> meth_as_iterator e + + and as_iterator (e : B.expr) : iterator option = + let result = as_iterator' e in + (* UB.Debug.expr ~label:"as_iterator" e; *) + (* " = " ^ [%show: iterator option] result |> Stdio.prerr_endline; *) + result + + and meth_as_iterator (e : B.expr) : iterator option = + let* f, args = + match e.e with + | App { f = { e = GlobalVar f; _ }; args; _ } -> Some (f, args) + | _ -> None + in + let f_eq n = Global_ident.eq_name n f in + let one_arg () = match args with [ x ] -> Some x | _ -> None in + let two_args () = match args with [ x; y ] -> Some (x, y) | _ -> None in + if f_eq Core__iter__traits__iterator__Iterator__step_by then + let* it, n = two_args () in + let* it = as_iterator it in + Some (StepBy { n; it }) + else if + f_eq Core__iter__traits__collect__IntoIterator__into_iter + || f_eq Core__slice__Impl__iter + then + let* iterable = one_arg () in + match iterable.typ with + | TSlice _ | TArray _ -> Some (Slice iterable) + | _ -> as_iterator iterable + else if f_eq Core__iter__traits__iterator__Iterator__enumerate then + let* iterable = one_arg () in + let* iterator = as_iterator iterable in + Some (Enumerate iterator) + else if f_eq Core__slice__Impl__chunks_exact then + let* slice, size = two_args () in + Some (ChunksExact { size; slice }) + else None + + let fn_args_of_iterator (it : iterator) : + (Concrete_ident.name * B.expr list * B.ty) option = + let open Concrete_ident_generated in + let usize = B.TInt { size = SSize; signedness = Unsigned } in + match it with + | Enumerate (ChunksExact { size; slice }) -> + Some + ( Rust_primitives__hax__folds__fold_enumerated_chunked_slice, + [ size; slice ], + usize ) + | Enumerate (Slice slice) -> + Some + ( Rust_primitives__hax__folds__fold_enumerated_slice, + [ slice ], + usize ) + | StepBy { n; it = Range { start; end_ } } -> + Some + ( Rust_primitives__hax__folds__fold_range_step_by, + [ start; end_; n ], + start.typ ) + | Range { start; end_ } -> + Some + (Rust_primitives__hax__folds__fold_range, [ start; end_ ], start.typ) + | _ -> None + [%%inline_defs dmutability] let rec dexpr_unwrapped (expr : A.expr) : B.expr = @@ -46,23 +167,31 @@ struct _; } -> let body = dexpr body in + let { body; invariant } = extract_loop_invariant body in let it = dexpr it in let pat = dpat pat in let bpat = dpat bpat in - let fn : B.expr' = - Closure { params = [ bpat; pat ]; body; captures = [] } - in - let fn : B.expr = - { - e = fn; - typ = TArrow ([ bpat.typ; pat.typ ], body.typ); - span = body.span; - } + let fn : B.expr = UB.make_closure [ bpat; pat ] body body.span in + let init = dexpr init in + let f, kind, args = + match as_iterator it |> Option.bind ~f:fn_args_of_iterator with + | Some (f, args, typ) -> + let invariant : B.expr = + let default = + let span = expr.span in + let pat = UB.make_wild_pat typ span in + (pat, B.{ e = Literal (Bool true); typ = TBool; span }) + in + let pat, invariant = Option.value ~default invariant in + UB.make_closure [ bpat; pat ] invariant invariant.span + in + (f, Concrete_ident.Kind.Value, args @ [ invariant; init; fn ]) + | None -> + ( Core__iter__traits__iterator__Iterator__fold, + AssociatedItem Value, + [ it; init; fn ] ) in - UB.call ~kind:(AssociatedItem Value) - Core__iter__traits__iterator__Iterator__fold - [ it; dexpr init; fn ] - span (dty span expr.typ) + UB.call ~kind f args span (dty span expr.typ) | Loop { body; diff --git a/engine/lib/phases/phase_hoist_disjunctive_patterns.ml b/engine/lib/phases/phase_hoist_disjunctive_patterns.ml new file mode 100644 index 000000000..332a094d8 --- /dev/null +++ b/engine/lib/phases/phase_hoist_disjunctive_patterns.ml @@ -0,0 +1,114 @@ +(* This phase transforms deep disjunctive patterns in equivalent + shallow ones. For example `Some(1 | 2)` becomes `Some(1) | Some(2)` *) + +open! Prelude + +module Make (F : Features.T) = + Phase_utils.MakeMonomorphicPhase + (F) + (struct + let phase_id = Diagnostics.Phase.HoistDisjunctions + + open Ast.Make (F) + module U = Ast_utils.Make (F) + module Visitors = Ast_visitors.Make (F) + + module Error = Phase_utils.MakeError (struct + let ctx = Diagnostics.Context.Phase phase_id + end) + + let hoist_disjunctions = + object (self) + inherit [_] Visitors.map + + method! visit_pat () p = + let return_pat p' = { p = p'; span = p.span; typ = p.typ } in + + (* When there is a list of subpaterns, we use the distributivity of nested + disjunctions: (a | b, c | d) gives (a, c) | (a, d) | (b, c) | (b,d) *) + let rec treat_args cases = function + | { p = POr { subpats }; _ } :: tail -> + treat_args + (List.concat_map + ~f:(fun subpat -> + List.map ~f:(fun args -> subpat :: args) cases) + subpats) + tail + | pat :: tail -> + let pat = self#visit_pat () pat in + treat_args (List.map ~f:(fun args -> pat :: args) cases) tail + | [] -> cases + in + let subpats_to_disj subpats = + match subpats with + | [ pat ] -> pat + | _ -> POr { subpats } |> return_pat + in + + (* When there is one subpattern, we check if it is a disjunction, + and if it is, we hoist it. *) + let treat_subpat pat to_pattern = + let subpat = self#visit_pat () pat in + match subpat with + | { p = POr { subpats }; span; _ } -> + return_pat + (POr + { + subpats = + List.map + ~f:(fun pat -> + { p = to_pattern pat; span; typ = p.typ }) + subpats; + }) + | _ -> p + in + + match p.p with + | PConstruct { name; args; is_record; is_struct } -> + let args_as_pat = + List.rev_map args ~f:(fun arg -> self#visit_pat () arg.pat) + in + let subpats = + List.map (treat_args [ [] ] args_as_pat) + ~f:(fun args_as_pat -> + let args = + List.map2_exn args_as_pat args + ~f:(fun pat { field; _ } -> { field; pat }) + in + PConstruct { name; args; is_record; is_struct } + |> return_pat) + in + + subpats_to_disj subpats + | PArray { args } -> + let subpats = + List.map + ~f:(fun args -> PArray { args } |> return_pat) + (treat_args [ [] ] + (List.rev_map args ~f:(fun arg -> self#visit_pat () arg))) + in + subpats_to_disj subpats + | POr { subpats } -> + let subpats = List.map ~f:(self#visit_pat ()) subpats in + POr + { + subpats = + List.concat_map + ~f:(function + | { p = POr { subpats }; _ } -> subpats | p -> [ p ]) + subpats; + } + |> return_pat + | PAscription { typ; typ_span; pat } -> + treat_subpat pat (fun pat -> PAscription { typ; typ_span; pat }) + | PBinding { subpat = Some (pat, as_pat); mut; mode; typ; var } -> + treat_subpat pat (fun pat -> + PBinding + { subpat = Some (pat, as_pat); mut; mode; typ; var }) + | PDeref { subpat; witness } -> + treat_subpat subpat (fun subpat -> PDeref { subpat; witness }) + | PWild | PConstant _ | PBinding { subpat = None; _ } -> p + end + + let ditems = List.map ~f:(hoist_disjunctions#visit_item ()) + end) diff --git a/engine/lib/phases/phase_hoist_disjunctive_patterns.mli b/engine/lib/phases/phase_hoist_disjunctive_patterns.mli new file mode 100644 index 000000000..f3585724a --- /dev/null +++ b/engine/lib/phases/phase_hoist_disjunctive_patterns.mli @@ -0,0 +1,5 @@ +(** This phase eliminates nested disjunctive patterns (leaving + only shallow disjunctions). It moves the disjunctions up + to the top-level pattern. *) + +module Make : Phase_utils.UNCONSTRAINTED_MONOMORPHIC_PHASE diff --git a/engine/lib/phases/phase_newtype_as_refinement.ml b/engine/lib/phases/phase_newtype_as_refinement.ml index a80e94a5c..da9c47685 100644 --- a/engine/lib/phases/phase_newtype_as_refinement.ml +++ b/engine/lib/phases/phase_newtype_as_refinement.ml @@ -21,13 +21,15 @@ module Make (F : Features.T) = inherit [_] Visitors.map as super method! visit_expr () e = + let e = super#visit_expr () e in match e.e with | App { f = { e = GlobalVar f; _ }; args = [ inner ]; _ } when Ast.Global_ident.eq_name Hax_lib__Refinement__new f || Ast.Global_ident.eq_name Hax_lib__RefineAs__into_checked f + || Ast.Global_ident.eq_name Hax_lib__Refinement__get_mut f || Ast.Global_ident.eq_name Hax_lib__Refinement__get f -> { e with e = Ascription { typ = e.typ; e = inner } } - | _ -> super#visit_expr () e + | _ -> e method! visit_item () i = match i.v with diff --git a/engine/lib/phases/phase_reconstruct_asserts.ml b/engine/lib/phases/phase_reconstruct_asserts.ml new file mode 100644 index 000000000..6701c1942 --- /dev/null +++ b/engine/lib/phases/phase_reconstruct_asserts.ml @@ -0,0 +1,163 @@ +open! Prelude + +module Make (F : Features.T) = + Phase_utils.MakeMonomorphicPhase + (F) + (struct + let phase_id = Diagnostics.Phase.ResugarAsserts + + open Ast.Make (F) + module U = Ast_utils.Make (F) + module Visitors = Ast_visitors.Make (F) + + module Error = Phase_utils.MakeError (struct + let ctx = Diagnostics.Context.Phase phase_id + end) + + let reconstruct_assert = + object (self) + inherit [_] Visitors.map as super + + method! visit_expr () e = + match e with + | { + e = + If + { + cond; + then_ = + { + e = + ( App + { + f = { e = GlobalVar nta; _ }; + args = + [ + { + e = + Let + { + body = + { + e = + Block + ( { + e = + App + { + f = + { + e = + GlobalVar + panic; + _; + }; + _; + }; + _; + }, + _ ); + _; + }; + _; + }; + _; + }; + ]; + _; + } + | Block + ( { + e = + App + { + f = { e = GlobalVar nta; _ }; + args = + [ + { + e = + App + { + f = + { e = GlobalVar panic; _ }; + _; + }; + _; + }; + ]; + _; + }; + _; + }, + _ ) ); + _; + }; + _; + }; + _; + } + when Ast.Global_ident.eq_name Rust_primitives__hax__never_to_any + nta + && (Ast.Global_ident.eq_name Core__panicking__panic panic + || Ast.Global_ident.eq_name Core__panicking__assert_failed + panic) -> + let cond_expr = self#visit_expr () cond in + + let prop = + match cond_expr.e with + (* assert! and assert_eq! *) + | App { f = { e = GlobalVar fnot; _ }; args = [ prop ]; _ } + when Ast.Global_ident.eq_name Core__ops__bit__Not__not fnot + -> + prop + (* assert_ne! *) + | _ -> + { + cond_expr with + e = + App + { + f = + { + e = + GlobalVar + (Ast.Global_ident.of_name Value + Core__ops__bit__Not__not); + span = cond_expr.span; + typ = TArrow ([ TBool ], TBool); + }; + args = [ cond_expr ]; + generic_args = []; + bounds_impls = []; + trait = None; + }; + } + in + + { + e with + e = + App + { + f = + { + e = + GlobalVar + (Ast.Global_ident.of_name Value Hax_lib__assert); + span = e.span; + typ = + TArrow + ( [ TBool ], + TApp { ident = `TupleType 0; args = [] } ); + }; + args = [ prop ]; + generic_args = []; + bounds_impls = []; + trait = None; + }; + } + | _ -> super#visit_expr () e + end + + let ditems = List.map ~f:(reconstruct_assert#visit_item ()) + end) diff --git a/engine/lib/phases/phase_reconstruct_asserts.mli b/engine/lib/phases/phase_reconstruct_asserts.mli new file mode 100644 index 000000000..2c17a0074 --- /dev/null +++ b/engine/lib/phases/phase_reconstruct_asserts.mli @@ -0,0 +1,4 @@ +(** This phase recognizes desugared `assert!(...)` to rewrite + into `hax_lib::assert(..)`. *) + +module Make : Phase_utils.UNCONSTRAINTED_MONOMORPHIC_PHASE diff --git a/engine/lib/phases/phase_recontruct_for_index_loops.ml b/engine/lib/phases/phase_reconstruct_for_index_loops.ml similarity index 100% rename from engine/lib/phases/phase_recontruct_for_index_loops.ml rename to engine/lib/phases/phase_reconstruct_for_index_loops.ml diff --git a/engine/lib/phases/phase_reconstruct_for_index_loops.mli b/engine/lib/phases/phase_reconstruct_for_index_loops.mli new file mode 100644 index 000000000..ea1784307 --- /dev/null +++ b/engine/lib/phases/phase_reconstruct_for_index_loops.mli @@ -0,0 +1,18 @@ +open! Prelude + +module Make (F : Features.T) : sig + include module type of struct + module FA = F + + module FB = struct + include F + include Features.On.For_index_loop + end + + module A = Ast.Make (F) + module B = Ast.Make (FB) + module ImplemT = Phase_utils.MakePhaseImplemT (A) (B) + end + + include ImplemT.T +end diff --git a/engine/lib/phases/phase_reconstruct_question_marks.ml b/engine/lib/phases/phase_reconstruct_question_marks.ml index c5f0c855a..86cec7e96 100644 --- a/engine/lib/phases/phase_reconstruct_question_marks.ml +++ b/engine/lib/phases/phase_reconstruct_question_marks.ml @@ -113,7 +113,7 @@ module%inlined_contents Make (FA : Features.T) = struct { f = { e = GlobalVar f }; args = [ { e = LocalVar residual_var; _ } ]; - impl = Some impl; + trait = Some (impl, _); }; typ = return_typ; _; diff --git a/engine/lib/phases/phase_reject.ml b/engine/lib/phases/phase_reject.ml index 2371133e0..df2bb9e7e 100644 --- a/engine/lib/phases/phase_reject.ml +++ b/engine/lib/phases/phase_reject.ml @@ -98,3 +98,39 @@ module As_pattern (FA : Features.T) = struct let metadata = make_metadata AsPattern end) end + +module Dyn (FA : Features.T) = struct + module FB = struct + include FA + include Features.Off.Dyn + end + + include + Feature_gate.Make (FA) (FB) + (struct + module A = FA + module B = FB + include Feature_gate.DefaultSubtype + + let dyn = reject + let metadata = make_metadata Dyn + end) +end + +module Trait_item_default (FA : Features.T) = struct + module FB = struct + include FA + include Features.Off.Trait_item_default + end + + include + Feature_gate.Make (FA) (FB) + (struct + module A = FA + module B = FB + include Feature_gate.DefaultSubtype + + let trait_item_default = reject + let metadata = make_metadata TraitItemDefault + end) +end diff --git a/engine/lib/phases/phase_simplify_match_return.ml b/engine/lib/phases/phase_simplify_match_return.ml index 06ef17f22..378aa7744 100644 --- a/engine/lib/phases/phase_simplify_match_return.ml +++ b/engine/lib/phases/phase_simplify_match_return.ml @@ -44,6 +44,7 @@ module Make (F : Features.T) = span = return_span; _; }; + guard = None; _; }; _; @@ -89,7 +90,9 @@ module Make (F : Features.T) = Let { monadic = None; lhs; rhs = arm_body; body }; } ) in - let arm = { arm with arm = { arm_pat; body = let_expr } } in + let arm = + { arm with arm = { arm_pat; body = let_expr; guard = None } } + in let diverging_arm = { diverging_arm with diff --git a/engine/lib/phases/phase_simplify_question_marks.ml b/engine/lib/phases/phase_simplify_question_marks.ml index 7426b15b9..aafabd067 100644 --- a/engine/lib/phases/phase_simplify_question_marks.ml +++ b/engine/lib/phases/phase_simplify_question_marks.ml @@ -136,7 +136,7 @@ module%inlined_contents Make (FA : Features.T) = struct { f = { e = GlobalVar f }; args = [ { e = LocalVar residual_var; _ } ]; - impl = Some impl; + trait = Some (impl, _); }; typ = return_typ; _; @@ -229,7 +229,7 @@ module%inlined_contents Make (FA : Features.T) = struct let body = { typ = local_success; e = LocalVar var_ok; span } in - { arm = { arm_pat; body }; span } + { arm = { arm_pat; body; guard = None }; span } in let arm_err = let pat = UA.make_var_pat var_err local_err span in @@ -248,7 +248,7 @@ module%inlined_contents Make (FA : Features.T) = struct in let e = Return { e = err; witness = return_witness } in let return = { typ = local_success; e; span } in - { arm = { arm_pat; body = return }; span } + { arm = { arm_pat; body = return; guard = None }; span } in let arms, typ = ([ arm_ok; arm_err ], local_success) in { e = Match { scrutinee = expr; arms }; typ; span } @@ -263,7 +263,7 @@ module%inlined_contents Make (FA : Features.T) = struct let body = { typ = local_success; e = LocalVar var_some; span } in - { arm = { arm_pat; body }; span } + { arm = { arm_pat; body; guard = None }; span } in let arm_none = let arm_pat = mk_cons Core__option__Option__None [] in @@ -273,7 +273,7 @@ module%inlined_contents Make (FA : Features.T) = struct in let e = Return { e = none; witness = return_witness } in let return = { typ = local_success; e; span } in - { arm = { arm_pat; body = return }; span } + { arm = { arm_pat; body = return; guard = None }; span } in let arms, typ = ([ arm_some; arm_none ], local_success) in { e = Match { scrutinee = expr; arms }; typ; span } diff --git a/engine/lib/phases/phase_specialize.ml b/engine/lib/phases/phase_specialize.ml index fc8021dd1..a3bde5b6f 100644 --- a/engine/lib/phases/phase_specialize.ml +++ b/engine/lib/phases/phase_specialize.ml @@ -134,7 +134,7 @@ module Make (F : Features.T) = { f; args = l; - impl = None; + trait = None; generic_args = []; bounds_impls = []; }; diff --git a/engine/lib/phases/phase_traits_specs.ml b/engine/lib/phases/phase_traits_specs.ml index 3789ada31..be0c4593b 100644 --- a/engine/lib/phases/phase_traits_specs.ml +++ b/engine/lib/phases/phase_traits_specs.ml @@ -28,8 +28,8 @@ module Make (F : Features.T) = let v = match item.v with | Trait { name; generics; items } -> - let f (item : trait_item) = - let mk kind = + let f attrs (item : trait_item) = + let mk role kind = let ti_ident = mk_name item.ti_ident kind in { item with @@ -38,23 +38,49 @@ module Make (F : Features.T) = [ Attr_payloads.to_attr TraitMethodNoPrePost item.ti_span; - ]; + ] + @ (List.filter + ~f: + [%matches? + Types.AssociatedItem { role = role'; _ }, _ when + [%eq: Types.ha_assoc_role] role role'] + attrs + |> List.map ~f:(uncurry Attr_payloads.to_attr)); } in match item.ti_v with | TIFn (TArrow (inputs, output)) -> [ - { (mk "pre") with ti_v = TIFn (TArrow (inputs, TBool)) }; { - (mk "post") with + (mk Types.Requires "pre") with + ti_v = TIFn (TArrow (inputs, TBool)); + }; + { + (mk Types.Ensures "post") with ti_v = TIFn (TArrow (inputs @ [ output ], TBool)); }; ] | TIFn _ -> [ (* REFINEMENTS FOR CONSTANTS? *) ] | TIType _ -> [ (* TODO REFINEMENTS FOR TYPES *) ] + | TIDefault _ -> [ (* TODO REFINEMENTS FOR DEFAULT ITEMS *) ] in let items = - List.concat_map ~f:(fun item -> f item @ [ item ]) items + List.concat_map + ~f:(fun item -> + let attrs = Attr_payloads.payloads item.ti_attrs in + let ti_attrs = + attrs + |> List.filter + ~f: + (fst + >> [%matches? + Types.AssociatedItem + { role = Ensures | Requires; _ }] + >> not) + |> List.map ~f:(uncurry Attr_payloads.to_attr) + in + f attrs item @ [ { item with ti_attrs } ]) + items in Trait { name; generics; items } | Impl { generics; self_ty; of_trait; items; parent_bounds } -> @@ -93,8 +119,8 @@ module Make (F : Features.T) = IIFn { body = - Attrs.associated_expr_rebinding params_pat - Requires item.ii_attrs + Attrs.associated_expr_rebinding item.ii_span + params_pat Requires item.ii_attrs |> Option.value ~default; params; }; @@ -105,7 +131,7 @@ module Make (F : Features.T) = IIFn { body = - Attrs.associated_expr_rebinding + Attrs.associated_expr_rebinding item.ii_span (params_pat @ [ pat ]) Ensures item.ii_attrs |> Option.value ~default; params = params @ [ out ]; diff --git a/engine/lib/phases/phase_transform_hax_lib_inline.ml b/engine/lib/phases/phase_transform_hax_lib_inline.ml index 0d448aa6a..d807212ac 100644 --- a/engine/lib/phases/phase_transform_hax_lib_inline.ml +++ b/engine/lib/phases/phase_transform_hax_lib_inline.ml @@ -80,7 +80,8 @@ module%inlined_contents Make (F : Features.T) = struct and quote_of_expr' span (expr : A.expr') = match expr with | App { f = { e = GlobalVar f; _ }; args = [ payload ]; _ } - when Global_ident.eq_name Hax_lib__inline f -> + when Global_ident.eq_name Hax_lib__inline f + || Global_ident.eq_name Hax_lib__inline_unsafe f -> let bindings, str = dexpr payload |> UB.collect_let_bindings in let str = match diff --git a/engine/lib/print_rust.ml b/engine/lib/print_rust.ml index 653e67475..900921b62 100644 --- a/engine/lib/print_rust.ml +++ b/engine/lib/print_rust.ml @@ -76,10 +76,8 @@ module Raw = struct | String s -> "\"" ^ String.escaped s ^ "\"" | Char c -> "'" ^ Char.to_string c ^ "'" | Int { value; _ } -> value - | Float { value; kind = F32; negative } -> - pnegative negative ^ value ^ "f32" - | Float { value; kind = F64; negative } -> - pnegative negative ^ value ^ "f64" + | Float { value; kind; negative } -> + pnegative negative ^ value ^ show_float_kind kind | Bool b -> Bool.to_string b let pprimitive_ident span : _ -> AnnotatedString.t = @@ -168,6 +166,19 @@ module Raw = struct !"arrow!(" & arrow & !")" | TAssociatedType _ -> !"proj_asso_type!()" | TOpaque ident -> !(Concrete_ident_view.show ident) + | TDyn { goals; _ } -> + let goals = + concat ~sep:!" + " (List.map ~f:(pdyn_trait_goal span) goals) + in + !"dyn(" & goals & !")" + + and pdyn_trait_goal span { trait; non_self_args } = + let ( ! ) = pure span in + let args = + List.map ~f:(pgeneric_value span) non_self_args |> concat ~sep:!", " + in + !(Concrete_ident_view.show trait) + & if List.is_empty args then empty else !"<" & args & !">" and pgeneric_value span (e : generic_value) : AnnotatedString.t = match e with @@ -267,12 +278,21 @@ module Raw = struct | Match { scrutinee; arms } -> let arms = List.map - ~f:(fun { arm = { arm_pat; body }; _ } -> - ppat arm_pat & !" => {" & pexpr body & !"}") + ~f:(fun { arm = { arm_pat; body; guard }; _ } -> + let guard : t = + guard + |> Option.map + ~f: + (fun { guard = IfLet { lhs; rhs; _ }; _ } -> + !" if let " & ppat lhs & !" = " & pexpr rhs + : guard -> t) + |> Option.value ~default:!"" + in + ppat arm_pat & guard & !" => {" & pexpr body & !"}") arms |> concat ~sep:!"," in - !"(match " & pexpr scrutinee & !" {" & arms & !"})" + !"(match (" & pexpr scrutinee & !") {" & arms & !"})" (* | Let { monadic = Some _; _ } -> !"monadic_let!()" *) | Let { monadic; lhs; rhs; body } -> (* TODO: here, [rhs.typ]! *) @@ -280,7 +300,7 @@ module Raw = struct let rhs_typ = pty rhs.span rhs.typ in let note = if String.equal (to_string lhs_typ) (to_string rhs_typ) then !"" - else !"// Note: rhs.typ=" & rhs_typ & !"\n" + else !"#[note(\"rhs.typ=" & rhs_typ & !"\")]\n" in let monadic = match monadic with @@ -399,6 +419,10 @@ module Raw = struct match p with | GCLifetime _ -> !"'unk: 'unk" | GCType { goal; _ } -> !"_:" & ptrait_goal span goal + | GCProjection { assoc_item; typ; _ } -> + !"_:_<_>::" + & !(Concrete_ident_view.show assoc_item) + & !"==" & pty span typ let pgeneric_constraints span (constraints : generic_constraint list) = if List.is_empty constraints then empty @@ -434,11 +458,22 @@ module Raw = struct let ( ! ) = pure span in concat ~sep:!", " (List.map ~f:(pvariant span) variants) + let pparam span ({ pat; typ; typ_span; attrs } : param) = + let ( ! ) = pure span in + pattrs attrs & ppat pat & !": " + & pty (Option.value ~default:pat.span typ_span) typ + + let pparams span (l : param list) = + let ( ! ) = pure span in + !"(" & List.map ~f:(pparam span) l |> concat ~sep:!"," & !")" + let ptrait_item (ti : trait_item) = let ( ! ) = pure ti.ti_span in let generics = pgeneric_params ti.ti_generics.params in let bounds = pgeneric_constraints ti.ti_span ti.ti_generics.constraints in let ident = !(Concrete_ident_view.to_definition_name ti.ti_ident) in + pattrs ti.ti_attrs + & match ti.ti_v with | TIType _ -> !"type " & ident & !": TodoPrintRustBoundsTyp;" | TIFn ty -> @@ -454,15 +489,15 @@ module Raw = struct in !"fn " & ident & generics & !"(" & params & !") -> " & return_type & bounds & !";" - - let pparam span ({ pat; typ; typ_span; attrs } : param) = - let ( ! ) = pure span in - pattrs attrs & ppat pat & !": " - & pty (Option.value ~default:pat.span typ_span) typ - - let pparams span (l : param list) = - let ( ! ) = pure span in - !"(" & List.map ~f:(pparam span) l |> concat ~sep:!"," & !")" + | TIDefault { params; body; _ } -> + let params = pparams ti.ti_span params in + let generics_constraints = + pgeneric_constraints ti.ti_span ti.ti_generics.constraints + in + let return_type = pty ti.ti_span body.typ in + let body = pexpr body in + !"fn " & ident & generics & !"(" & params & !") -> " & return_type + & generics_constraints & !"{" & body & !"}" let pimpl_item (ii : impl_item) = let span = ii.ii_span in @@ -470,6 +505,8 @@ module Raw = struct let generics = pgeneric_params ii.ii_generics.params in let bounds = pgeneric_constraints span ii.ii_generics.constraints in let ident = !(Concrete_ident_view.to_definition_name ii.ii_ident) in + pattrs ii.ii_attrs + & match ii.ii_v with | IIType _ -> !"type " & ident & !": TodoPrintRustBoundsTyp;" | IIFn { body; params } -> @@ -540,29 +577,31 @@ module Raw = struct in pattrs e.attrs & pi with NotImplemented -> - !("\n/* print_rust: pitem: not implemented (item: " + !("\n/** print_rust: pitem: not implemented (item: " ^ [%show: concrete_ident] e.ident - ^ ") */\n") + ^ ") */\nconst _: () = ();\n") end let rustfmt (s : string) : string = - let open Utils.Command in - let { stderr; stdout } = run "rustfmt" s in - if String.is_empty stderr then stdout - else - let err = - [%string - "\n\n\ - #######################################################\n\ - ########### WARNING: Failed running rustfmt ###########\n\ - #### STDOUT:\n\ - %{stdout}\n\ - #### STDERR:\n\ - %{stderr}\n\ - #######################################################\n"] - in - Stdio.prerr_endline err; - [%string "/*\n%{err}\n*/\n\n%{s}"] + match + Hax_io.request (PrettyPrintRust s) ~expected:"PrettyPrintedRust" (function + | Types.PrettyPrintedRust s -> Some s + | _ -> None) + with + | Ok formatted -> formatted + | Err error -> + let err = + [%string + "\n\n\ + #######################################################\n\ + ########### WARNING: Failed formatting ###########\n\ + %{error}\n\ + STRING:\n\ + %{s}\n\ + #######################################################\n"] + in + Stdio.prerr_endline err; + s exception RetokenizationFailure diff --git a/engine/lib/side_effect_utils.ml b/engine/lib/side_effect_utils.ml index 44799d3e0..aefa25663 100644 --- a/engine/lib/side_effect_utils.ml +++ b/engine/lib/side_effect_utils.ml @@ -347,7 +347,7 @@ struct m#plus (m#plus (no_lbs ethen) (no_lbs eelse)) effects in ({ e with e = If { cond; then_; else_ } }, effects)) - | App { f; args; generic_args; impl; bounds_impls } -> + | App { f; args; generic_args; trait; bounds_impls } -> HoistSeq.many env (List.map ~f:(self#visit_expr env) (f :: args)) (fun l effects -> @@ -358,7 +358,7 @@ struct in ( { e with - e = App { f; args; generic_args; impl; bounds_impls }; + e = App { f; args; generic_args; trait; bounds_impls }; }, effects )) | Literal _ -> (e, m#zero) diff --git a/engine/lib/span.ml b/engine/lib/span.ml index d6ff6f4c9..2704d8762 100644 --- a/engine/lib/span.ml +++ b/engine/lib/span.ml @@ -19,7 +19,6 @@ module Imported = struct | Anon of string | MacroExpansion of string | ProcMacroSourceCode of string - | CfgSpec of string | CliCrateAttr of string | Custom of string | DocTest of string @@ -41,7 +40,6 @@ module Imported = struct | Anon x -> Anon x | MacroExpansion x -> MacroExpansion x | ProcMacroSourceCode x -> ProcMacroSourceCode x - | CfgSpec x -> CfgSpec x | CliCrateAttr x -> CliCrateAttr x | Custom x -> Custom x | DocTest x -> DocTest x @@ -68,7 +66,6 @@ module Imported = struct | Anon x -> Anon x | MacroExpansion x -> MacroExpansion x | ProcMacroSourceCode x -> ProcMacroSourceCode x - | CfgSpec x -> CfgSpec x | CliCrateAttr x -> CliCrateAttr x | Custom x -> Custom x | DocTest x -> DocTest x diff --git a/engine/lib/subtype.ml b/engine/lib/subtype.ml index f58487482..a2fc68e19 100644 --- a/engine/lib/subtype.ml +++ b/engine/lib/subtype.ml @@ -47,6 +47,18 @@ struct | TOpaque ident -> TOpaque ident | TRawPointer { witness } -> TRawPointer { witness = S.raw_pointer span witness } + | TDyn { witness; goals } -> + TDyn + { + witness = S.dyn span witness; + goals = List.map ~f:(ddyn_trait_goal span) goals; + } + + and ddyn_trait_goal (span : span) (r : A.dyn_trait_goal) : B.dyn_trait_goal = + { + trait = r.trait; + non_self_args = List.map ~f:(dgeneric_value span) r.non_self_args; + } and dtrait_goal (span : span) (r : A.trait_goal) : B.trait_goal = { trait = r.trait; args = List.map ~f:(dgeneric_value span) r.args } @@ -54,6 +66,14 @@ struct and dimpl_ident (span : span) (r : A.impl_ident) : B.impl_ident = { goal = dtrait_goal span r.goal; name = r.name } + and dprojection_predicate (span : span) (r : A.projection_predicate) : + B.projection_predicate = + { + impl = dimpl_expr span r.impl; + assoc_item = r.assoc_item; + typ = dty span r.typ; + } + and dimpl_expr (span : span) (i : A.impl_expr) : B.impl_expr = match i with | Self -> Self @@ -157,14 +177,15 @@ struct then_ = dexpr then_; else_ = Option.map ~f:dexpr else_; } - | App { f; args; generic_args; bounds_impls; impl } -> + | App { f; args; generic_args; bounds_impls; trait } -> + let dgeneric_values = List.map ~f:(dgeneric_value span) in App { f = dexpr f; args = List.map ~f:dexpr args; - generic_args = List.map ~f:(dgeneric_value span) generic_args; + generic_args = dgeneric_values generic_args; bounds_impls = List.map ~f:(dimpl_expr span) bounds_impls; - impl = Option.map ~f:(dimpl_expr span) impl; + trait = Option.map ~f:(dimpl_expr span *** dgeneric_values) trait; } | Literal lit -> Literal lit | Array l -> Array (List.map ~f:dexpr l) @@ -296,10 +317,27 @@ struct witness = S.state_passing_loop span s.witness; } - and darm (a : A.arm) : B.arm = { span = a.span; arm = darm' a.span a.arm } + and darm (a : A.arm) : B.arm = { span = a.span; arm = darm' a.arm } + + and darm' (a : A.arm') : B.arm' = + { + arm_pat = dpat a.arm_pat; + body = dexpr a.body; + guard = Option.map ~f:dguard a.guard; + } + + and dguard (a : A.guard) : B.guard = + { span = a.span; guard = dguard' a.span a.guard } - and darm' (_span : span) (a : A.arm') : B.arm' = - { arm_pat = dpat a.arm_pat; body = dexpr a.body } + and dguard' (span : span) (guard : A.guard') : B.guard' = + match guard with + | IfLet { lhs; rhs; witness } -> + IfLet + { + lhs = dpat lhs; + rhs = dexpr rhs; + witness = S.match_guard span witness; + } and dlhs (span : span) (lhs : A.lhs) : B.lhs = match lhs with @@ -342,6 +380,8 @@ struct match generic_constraint with | GCLifetime (lf, witness) -> B.GCLifetime (lf, S.lifetime span witness) | GCType impl_ident -> B.GCType (dimpl_ident span impl_ident) + | GCProjection projection -> + B.GCProjection (dprojection_predicate span projection) let dgenerics (span : span) (g : A.generics) : B.generics = { @@ -369,6 +409,13 @@ struct match ti with | TIType idents -> TIType (List.map ~f:(dimpl_ident span) idents) | TIFn t -> TIFn (dty span t) + | TIDefault { params; body; witness } -> + TIDefault + { + params = List.map ~f:(dparam span) params; + body = dexpr body; + witness = S.trait_item_default span witness; + } and dtrait_item (ti : A.trait_item) : B.trait_item = { diff --git a/engine/lib/utils.ml b/engine/lib/utils.ml index a5fb74ab8..2c95d2f88 100644 --- a/engine/lib/utils.ml +++ b/engine/lib/utils.ml @@ -82,26 +82,6 @@ let sequence (l : 'a option list) : 'a list option = let tabsize = 2 let newline_indent depth : string = "\n" ^ String.make (tabsize * depth) ' ' -module Command = struct - type output = { stderr : string; stdout : string } - - let run (command : string) (stdin_string : string) : output = - let stdout, stdin, stderr = - Unix.open_process_full command (Unix.environment ()) - in - Unix.set_close_on_exec @@ Unix.descr_of_in_channel stdout; - Unix.set_close_on_exec @@ Unix.descr_of_in_channel stderr; - Out_channel.( - output_string stdin stdin_string; - flush stdin; - close stdin); - let strout = In_channel.input_all stdout in - let strerr = In_channel.input_all stderr |> Stdlib.String.trim in - Unix.close @@ Unix.descr_of_in_channel stdout; - Unix.close @@ Unix.descr_of_in_channel stderr; - { stdout = strout; stderr = strerr } -end - module MyInt64 = struct include Base.Int64 @@ -113,3 +93,25 @@ module MyInt64 = struct let yojson_of_t (int64 : t) : Yojson.Safe.t = `Intlit (to_string int64) end + +include ( + struct + let id = ref 0 + + let tempfile_path ~suffix = + id := !id + 1; + Core.Filename.( + concat temp_dir_name ("hax-debug-" ^ Int.to_string !id ^ suffix)) + end : + sig + val tempfile_path : suffix:string -> string + (** Generates a temporary file path that ends with `suffix` *) + end) + +module List = struct + include Base.List + + let zip_opt : 'a 'b. 'a list -> 'b list -> ('a * 'b) list option = + fun x y -> + match zip x y with Ok result -> Some result | Unequal_lengths -> None +end diff --git a/engine/names/Cargo.toml b/engine/names/Cargo.toml index 5213e4707..efc92fca6 100644 --- a/engine/names/Cargo.toml +++ b/engine/names/Cargo.toml @@ -11,4 +11,4 @@ description = "Dummy crate containing all the Rust names the hax engine should b [dependencies] hax-lib-protocol = {path = "../../hax-lib-protocol"} -hax-lib = {path = "../../hax-lib"} \ No newline at end of file +hax-lib = {path = "../../hax-lib"} diff --git a/engine/names/extract/Cargo.toml b/engine/names/extract/Cargo.toml index 3c845ec32..c6f9dacb6 100644 --- a/engine/names/extract/Cargo.toml +++ b/engine/names/extract/Cargo.toml @@ -11,14 +11,16 @@ description = "Helper binary generating an OCaml module" [build-dependencies] -hax-cli-options-engine.workspace = true serde.workspace = true serde_json.workspace = true -cargo_metadata.workspace = true hax-engine-names.workspace = true +hax-adt-into.workspace = true tempfile.version = "3.9" -camino = "1.1" +bincode.workspace = true [features] default = ["extract_names_mode"] extract_names_mode = [] + +[lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = ['cfg(feature, values("rustc"))'] } diff --git a/engine/names/extract/build.rs b/engine/names/extract/build.rs index 98a8dd55f..47e7fbc51 100644 --- a/engine/names/extract/build.rs +++ b/engine/names/extract/build.rs @@ -1,4 +1,3 @@ -use serde_json; use serde_json::Value; use std::process::{Command, Stdio}; @@ -46,11 +45,11 @@ fn def_path_item_to_str(path_item: DefPathItem) -> String { DefPathItem::ForeignMod => "ForeignMod".into(), DefPathItem::Use => "Use".into(), DefPathItem::GlobalAsm => "GlobalAsm".into(), - DefPathItem::ClosureExpr => "ClosureExpr".into(), + DefPathItem::Closure => "Closure".into(), DefPathItem::Ctor => "Ctor".into(), DefPathItem::AnonConst => "AnonConst".into(), - DefPathItem::ImplTrait => "ImplTrait".into(), - DefPathItem::ImplTraitAssocTy => "ImplTraitAssocTy".into(), + DefPathItem::OpaqueTy => "OpaqueTy".into(), + DefPathItem::AnonAdt => "AnonAdt".into(), } } @@ -125,13 +124,6 @@ fn reader_to_str(s: String) -> String { result } -fn target_dir(suffix: &str) -> camino::Utf8PathBuf { - let metadata = cargo_metadata::MetadataCommand::new().exec().unwrap(); - let mut dir = metadata.target_directory; - dir.push(suffix); - dir -} - fn get_json() -> String { let mut cmd = Command::new(std::env::var("HAX_CARGO_COMMAND_PATH").unwrap_or("cargo-hax".to_string())); @@ -150,10 +142,6 @@ fn get_json() -> String { .stdout(Stdio::piped()) .stderr(Stdio::piped()); - cmd.env("CARGO_TARGET_DIR", target_dir("hax")); - for env in ["DYLD_FALLBACK_LIBRARY_PATH", "LD_LIBRARY_PATH"] { - cmd.env_remove(env); - } let out = cmd.output().unwrap(); let stdout = String::from_utf8(out.stdout).unwrap(); let stderr = String::from_utf8(out.stderr).unwrap(); diff --git a/engine/names/src/lib.rs b/engine/names/src/lib.rs index 862afb7e0..438dd41f0 100644 --- a/engine/names/src/lib.rs +++ b/engine/names/src/lib.rs @@ -26,6 +26,10 @@ fn dummy_hax_concrete_ident_wrapper>(x: I, mu let _: Option<()> = None; let _ = Option::<()>::None.is_some(); let _: Result<(), u32> = Result::Err(3u8).map_err(u32::from); + assert!(true); + assert_eq!(1, 1); + hax_lib::assert!(true); + hax_lib::_internal_loop_invariant(|_: usize| true); let _ = [()].into_iter(); let _: u16 = 6u8.into(); @@ -34,6 +38,14 @@ fn dummy_hax_concrete_ident_wrapper>(x: I, mu let _ = ..; let _ = ..1; + fn iterator_functions(it: It) { + let _ = it.clone().step_by(2); + let _ = it.clone().enumerate(); + let _ = [()].chunks_exact(2); + let _ = [()].iter(); + let _ = (&[()] as &[()]).iter(); + } + { use hax_lib::int::*; let a: Int = 3u8.lift(); @@ -48,9 +60,11 @@ fn dummy_hax_concrete_ident_wrapper>(x: I, mu } let _ = hax_lib::inline(""); + let _: () = hax_lib::inline_unsafe(""); use hax_lib::{RefineAs, Refinement}; - fn refinements>(x: T, y: U) -> T { + fn refinements>(x: T, y: U) -> T { + let _ = x.clone().get_mut(); T::new(x.get()); y.into_checked() } @@ -158,6 +172,13 @@ mod hax { fn array_of_list() {} fn never_to_any() {} + mod folds { + fn fold_range() {} + fn fold_range_step_by() {} + fn fold_enumerated_slice() {} + fn fold_enumerated_chunked_slice() {} + } + /// The engine uses this `dropped_body` symbol as a marker value /// to signal that a item was extracted without body. fn dropped_body() {} diff --git a/engine/utils/generate_visitors/README.md b/engine/utils/generate_visitors/README.md new file mode 100644 index 000000000..5a77163d3 --- /dev/null +++ b/engine/utils/generate_visitors/README.md @@ -0,0 +1,14 @@ +# `generate_visitors` + +This binary reads the AST module of hax and creates **standalone** +visitors. We need to define visitors and the types of the AST in two +separate modules. Otherwise, each time we instantiate the AST functor, +we end up re-defining every single visitor. Since the AST functor is +instantiated a lot, this used to lead to huge memory consumption while +building. + +This binary takes an OCaml module that defines types as input and +outputs an OCaml module defining visitors for those types. + +Note that this binary relies on the structure and naming of the AST of +hax; it is not intended for any other use. diff --git a/engine/utils/generate_visitors/codegen_visitor.ml b/engine/utils/generate_visitors/codegen_visitor.ml new file mode 100644 index 000000000..9a8b62725 --- /dev/null +++ b/engine/utils/generate_visitors/codegen_visitor.ml @@ -0,0 +1,266 @@ +(** Give a list of {!Types.Datatype.t}, this file generates an ocaml +module of visitors. *) + +open Base +open Utils +open Types + +(** What kind of visitor are we generating? *) +type kind = Map | MapReduce | Reduce + +(** Helpers around kinds *) +include struct + let is_reduce = function MapReduce | Reduce -> true | _ -> false + let is_map = function Map | MapReduce -> true | _ -> false +end + +(** Various helpers and constants *) +include struct + let method_prefix = "visit_" + let acc_var_prefix = "acc___" + let acc_var_param = acc_var_prefix ^ "param___var" + let payload_var = "v___payload" + let env_var = "env___var" + let app = List.filter ~f:(String.is_empty >> not) >> String.concat ~sep:" " + let parens s = if String.contains s ' ' then "(" ^ s ^ ")" else s +end + +(** Produces a method name given a dot-separated path *) +let method_name path = + let path = String.split ~on:'.' path in + method_prefix ^ String.concat ~sep:"__" path + +(** Produces a visitor call for a type expression, without applying it. *) +let rec of_type' need_parens (t : Type.t) = + let f = + if String.is_prefix ~prefix:"'" t.typ then "visit_" ^ t.typ + else "self#" ^ method_name t.typ + in + if List.is_empty t.args then f + else + app (f :: List.map ~f:(of_type' true) t.args) + |> if need_parens then parens else Fn.id + +(** Produces a complete visitor call for a type expression. *) +let of_type typ payload = app [ of_type' false typ; env_var; payload ] + +let acc_var_for_field ((field, _) : Record.field) = acc_var_prefix ^ field + +(** Given a list [x1; ...; xN], produces `self#plus x1 (self#plus ... (self#plus xN))` *) +let self_plus = + List.fold_left + ~f:(fun acc var -> + match acc with + | None -> Some var + | Some acc -> Some (app [ "self#plus"; parens acc; var ])) + ~init:None + >> Option.value ~default:"self#zero" + +(** Creates a let expression *) +let mk_let ~lhs ~rhs = "let " ^ lhs ^ " = " ^ rhs ^ " in " + +let of_typed_binding ~kind (value, typ, value_binding, acc_binding) = + let lhs = + [ + (if is_map kind then [ value_binding ] else []); + (if is_reduce kind then [ acc_binding ] else []); + ] + |> List.concat |> String.concat ~sep:", " + in + let rhs = of_type typ value in + mk_let ~lhs ~rhs + +let of_typed_bindings ~kind l = + let lbs = List.map ~f:(of_typed_binding ~kind) l |> String.concat ~sep:"\n" in + let acc = List.map ~f:(fun (_, _, _, acc) -> acc) l |> self_plus in + (lbs, acc) + +let tuple_if ~kind ?(sep = ", ") if_map if_reduce = + [ + (if is_map kind then [ if_map ] else []); + (if is_reduce kind then [ if_reduce ] else []); + ] + |> List.concat |> String.concat ~sep + +let of_record ~kind ~constructor (r : Record.t) = + let lbs, acc = + List.map + ~f:(fun (field, typ) -> + (payload_var ^ "." ^ field, typ, field, acc_var_for_field (field, typ))) + r + |> of_typed_bindings ~kind + in + let record = + constructor ^ "{" ^ String.concat ~sep:"; " (List.map ~f:fst r) ^ "}" + in + let result = tuple_if ~kind record acc in + (* let result = record ^ if is_reduce kind then ", " ^ acc else "" in *) + lbs ^ "\n" ^ result + +let of_tuple_variant ~kind name (types : Type.t list) = + let vars = List.mapi ~f:(fun i _ -> "x" ^ Int.to_string i) types in + let accs = List.mapi ~f:(fun i _ -> "a" ^ Int.to_string i) types in + let tuple = vars |> String.concat ~sep:", " |> parens in + let lbs, acc = + List.zip_exn types (List.zip_exn vars accs) + |> List.map ~f:(fun (typ, (name, acc)) -> (name, typ, name, acc)) + |> of_typed_bindings ~kind + in + name ^ " " ^ tuple ^ " -> " ^ lbs ^ tuple_if ~kind (name ^ " " ^ tuple) acc + +let of_variant ~kind (v : Variant.t) = + match v.payload with + | Tuple l -> of_tuple_variant ~kind v.name l + | None -> v.name ^ " -> " ^ tuple_if ~kind v.name "self#zero" + | Record record -> + v.name ^ " " ^ payload_var ^ " -> " + ^ of_record ~kind ~constructor:v.name record + +let of_datatype ~kind (dt : Datatype.t) = + let body = + match dt.kind with + | Record record -> of_record ~kind ~constructor:"" record + | TypeSynonym typ -> of_type typ payload_var + | Variant variants -> + let arms = + List.map ~f:(of_variant ~kind) variants |> String.concat ~sep:"\n | " + in + "match " ^ payload_var ^ " with\n " ^ arms + | Opaque -> tuple_if ~kind payload_var "self#zero" + in + let meth = method_name dt.name in + let self_typ = + if Type.is_tuple_name dt.name then + String.concat ~sep:" * " dt.type_vars |> parens + else app [ String.concat ~sep:", " dt.type_vars |> parens; dt.name ] + in + let forall_clause = String.concat ~sep:" " dt.type_vars in + let arrs = + List.map + ~f:(fun tvar -> + "'env -> " ^ tvar ^ " -> " + ^ (tuple_if ~kind ~sep:" * " tvar "'acc" |> parens)) + dt.type_vars + in + let arrs = + arrs @ [ "'env"; self_typ; tuple_if ~kind ~sep:" * " self_typ "'acc" ] + in + let arrs = List.map ~f:parens arrs |> String.concat ~sep:" -> " in + let meth_typ = + List.filter ~f:(String.is_empty >> not) [ forall_clause; arrs ] + |> String.concat ~sep:"." + in + let visitors = + List.map ~f:(fun tvar -> "visit_" ^ tvar) dt.type_vars |> app + in + "method " ^ meth ^ " : " ^ meth_typ ^ " = fun " ^ visitors ^ " " ^ env_var + ^ " " ^ payload_var ^ " -> " ^ body + +(** Hard coded visitors *) +let extra_visitors_for = function + | Map -> + " method visit_list : 'a. ('env -> 'a -> 'a) -> 'env -> 'a list \ + -> 'a list\n\ + \ =\n\ + \ fun v env -> Base.List.map ~f:(v env)\n\n" + | MapReduce -> + " method visit_list\n\ + \ : 'a. ('env -> 'a -> 'a * 'acc) -> 'env -> 'a list -> 'a \ + list * 'acc\n\ + \ =\n\ + \ fun v env ->\n\ + \ Base.List.fold_map ~init:self#zero ~f:(fun acc x ->\n\ + \ let x, acc' = v env x in\n\ + \ (self#plus acc acc', x))\n\ + \ >> swap\n\n" + | Reduce -> + "\n\ + \ method visit_list : 'a. ('env -> 'a -> 'acc) -> 'env -> 'a \ + list -> 'acc =\n\ + \ fun v env this ->\n\ + \ Base.List.fold ~init:self#zero\n\ + \ ~f:(fun acc -> v env >> self#plus acc)\n\ + \ this" + +(** Make one kind of visitor *) +let mk_one ~kind (l : Datatype.t list) : string = + let contents = + List.map ~f:(of_datatype ~kind) l |> String.concat ~sep:"\n\n" + in + let name = + [ + (if is_map kind then [ "map" ] else []); + (if is_reduce kind then [ "reduce" ] else []); + ] + |> List.concat |> String.concat ~sep:"" + in + let extra_visitors = + (* visitor_for_tuples ~kind ^ "\n\n" ^ *) + extra_visitors_for kind + in + "class virtual ['self] " ^ name ^ " = object (self : 'self)" ^ contents ^ "\n" + ^ extra_visitors ^ "\nend" + +(** AST.ml-specific headers *) +let header = + "open Ast\n\ + open! Utils\n\ + open Base\n\n\ + module Make =\n\ + functor\n\ + \ (F : Features.T)\n\ + \ ->\n\ + \ struct\n\ + \ [@@@warning \"-27\"]\n\n\ + \ open Make (F)\n" + +(** Only certain types should be opaque in AST.ml *) +let is_allowed_opaque name = + let allowlist = + [ + "Local_ident.t"; + "bool"; + "char"; + "concrete_ident"; + "global_ident"; + "attr"; + "local_ident"; + "signedness"; + "size"; + "span"; + "string"; + "todo"; + "quote"; + "float_kind"; + "int_kind"; + ] + in + List.mem ~equal:String.equal allowlist name + || String.is_prefix ~prefix:"F." name + +(** Make all three kinds of visitors for a list of datatypes *) +let mk (l : Datatype.t list) : string = + let l = Primitive_types.(tuples @ [ option ]) @ l in + let opaques = + Visitors.collect_undefined_types l + |> List.map ~f:(fun name -> + Datatype.{ name; type_vars = []; kind = Opaque }) + in + (match + Visitors.collect_undefined_types l + |> List.filter ~f:(is_allowed_opaque >> not) + with + | [] -> () + | disallowed -> + let msg = + "visitor generation: forbidden opaque type: " + ^ [%show: string list] disallowed + in + Stdio.prerr_endline msg; + failwith msg); + let l = opaques @ l in + let visitors = + List.map ~f:(fun kind -> mk_one ~kind l) [ Map; MapReduce; Reduce ] + in + let visitors = visitors |> String.concat ~sep:"\n\n" in + [ header; visitors; "end" ] |> String.concat ~sep:"\n\n" diff --git a/engine/utils/generate_visitors/dune b/engine/utils/generate_visitors/dune new file mode 100644 index 000000000..8037a9a3c --- /dev/null +++ b/engine/utils/generate_visitors/dune @@ -0,0 +1,17 @@ +(executable + (public_name generate_visitors) + (name generate_visitors) + (package hax-engine) + (libraries ppxlib base stdio ppx_deriving_yojson.runtime) + (preprocess + (pps + ppxlib.metaquot + ppx_deriving.eq + ppx_yojson_conv + ppx_compare + ppx_deriving.show))) + +(env + (_ + (flags + (:standard -warn-error -A -warn-error +8)))) diff --git a/engine/utils/generate_visitors/errors.ml b/engine/utils/generate_visitors/errors.ml new file mode 100644 index 000000000..587b7a635 --- /dev/null +++ b/engine/utils/generate_visitors/errors.ml @@ -0,0 +1,56 @@ +open Ppxlib +open! Ppx_yojson_conv_lib.Yojson_conv.Primitives + +(** Define `pp_*` functions for some type of the OCaml ASTs so that we +can show them *) +include struct + let pp_core_type = Pprintast.core_type + + let pp_label_declaration fmt label_decl = + Stdlib.Format.pp_print_string fmt label_decl.pld_name.txt + + let pp_constructor_declaration fmt cons_decl = + Stdlib.Format.pp_print_string fmt cons_decl.pcd_name.txt + + let pp_type_declaration fmt type_decl = + Pprintast.structure_item fmt + { + pstr_loc = Astlib.Location.none; + pstr_desc = Pstr_type (Nonrecursive, [ type_decl ]); + } +end + +(** The type of various error that can occur errors *) +type t = + | UnsupportedCoreType of core_type + | UnsupportedLabelDeclaration of label_declaration + | UnsupportedConstructorDeclaration of constructor_declaration + | UnsupportedTypeDeclaration of type_declaration +[@@deriving show] + +(** We can't derive yojson for OCaml types. Thus this indirection, that prints payload of `t` as string, and *then* produces JSON. *) +open struct + type t_string = + | UnsupportedCoreType of string + | UnsupportedLabelDeclaration of string + | UnsupportedConstructorDeclaration of string + | UnsupportedTypeDeclaration of string + [@@deriving show, yojson] + + let into_string : t -> t_string = function + | UnsupportedCoreType core_type -> + UnsupportedCoreType ([%show: core_type] core_type) + | UnsupportedLabelDeclaration label_declaration -> + UnsupportedLabelDeclaration + ([%show: label_declaration] label_declaration) + | UnsupportedConstructorDeclaration constructor_declaration -> + UnsupportedConstructorDeclaration + ([%show: constructor_declaration] constructor_declaration) + | UnsupportedTypeDeclaration type_declaration -> + UnsupportedTypeDeclaration ([%show: type_declaration] type_declaration) +end + +let yojson_of_t (e : t) = into_string e |> [%yojson_of: t_string] +let _ = pp_t_string (* just to silence OCaml warning *) + +exception Error of t diff --git a/engine/utils/generate_visitors/generate_visitors.ml b/engine/utils/generate_visitors/generate_visitors.ml new file mode 100644 index 000000000..21f303d9e --- /dev/null +++ b/engine/utils/generate_visitors/generate_visitors.ml @@ -0,0 +1,30 @@ +open Base +open Utils +open Types + +let _main = + let ocaml_file = + Stdio.In_channel.stdin |> Lexing.from_channel + |> Ppxlib_ast.Parse.implementation + in + let datatypes = + type_declaration_of_structure ocaml_file + |> List.filter ~f:(fun (path, _) -> + (* We only look at certain types in the AST.ml module *) + String.is_prefix ~prefix:"Make." path + || List.mem ~equal:String.equal + [ "mutability"; "literal"; "attrs"; "quote" ] + path) + |> List.map ~f:(fun (path, td) -> + ( String.chop_prefix ~prefix:"Make." path + |> Option.value ~default:path, + td )) + |> List.map ~f:(fun (path, type_decl) -> + (path, Datatype.of_ocaml_result type_decl)) + |> List.filter_map ~f:(fun (path, dt) -> + match dt with + (* Use path as name, can be useful if used on something else than AST.ml *) + | Result.Ok v -> Some Datatype.{ v with name = path } + | _ -> None) + in + datatypes |> Codegen_visitor.mk |> Stdio.print_endline diff --git a/engine/utils/generate_visitors/primitive_types.ml b/engine/utils/generate_visitors/primitive_types.ml new file mode 100644 index 000000000..f57c4cf6b --- /dev/null +++ b/engine/utils/generate_visitors/primitive_types.ml @@ -0,0 +1,33 @@ +(** This module encodes several primitive OCaml types as Datatype.t so +that visitors can be generated automatically for them as well. *) + +open Base +open! Utils +open Types + +(** Helper to produce type variable. *) +let ty_var typ = Type.{ typ; args = [] } + +(** Produces a datatype description for tuples of a given length. *) +let mk_tuple len = + let type_vars = List.init len ~f:(fun i -> "'t" ^ Int.to_string i) in + let name = Type.tuple_name len in + let types = List.map ~f:ty_var type_vars in + let payload = VariantPayload.Tuple types in + let kind = Datatype.Variant [ Variant.{ name = ""; payload } ] in + Datatype.{ name; type_vars; kind } + +(** Common sizes of tuples. *) +let tuples = List.map ~f:mk_tuple [ 2; 3; 4 ] + +(** Datatype description for the option type. *) +let option = + let kind = + Datatype.Variant + [ + Variant. + { name = "Some"; payload = VariantPayload.Tuple [ ty_var "'a" ] }; + Variant.{ name = "None"; payload = VariantPayload.None }; + ] + in + Datatype.{ name = "option"; type_vars = [ "'a" ]; kind } diff --git a/engine/utils/generate_visitors/types.ml b/engine/utils/generate_visitors/types.ml new file mode 100644 index 000000000..391b6bb0c --- /dev/null +++ b/engine/utils/generate_visitors/types.ml @@ -0,0 +1,135 @@ +(** This module defines a subset of OCaml inductives as a nice and +simple AST *) + +open Base +open! Utils +open Errors + +(** Describe what is a type expression, reflects OCaml's `core_type`. *) +module Type = struct + let tuple_prefix = "prim___tuple_" + let is_tuple_name = String.is_prefix ~prefix:tuple_prefix + let tuple_name (len : int) : string = tuple_prefix ^ Int.to_string len + let unit_name : string = "unit___" + + let lident_to_string lident = + Astlib.Longident.flatten lident |> String.concat ~sep:"." + + type t = { typ : string; args : t list } [@@deriving show, yojson] + + let tuple args = + match args with + | [] -> { typ = unit_name; args } + | [ typ ] -> typ + | _ -> { typ = tuple_name (List.length args); args } + + let unsupported v = raise (Error (UnsupportedCoreType v)) + + open Ppxlib + + let rec of_ocaml (t : core_type) : t = + match t.ptyp_desc with + | Ptyp_var typ -> { typ = "'" ^ typ; args = [] } + | Ptyp_tuple types -> List.map ~f:of_ocaml types |> tuple + | Ptyp_constr (lident, types) -> + { typ = lident_to_string lident.txt; args = List.map ~f:of_ocaml types } + | _ -> unsupported t +end + +(** Describe what is a record, reflects OCaml's `label_declaration`. *) +module Record = struct + type field = string * Type.t [@@deriving show, yojson] + type t = field list [@@deriving show, yojson] + + let unsupported v = raise (Error (UnsupportedLabelDeclaration v)) + + open Ppxlib + + let field_of_ocaml (label_decl : label_declaration) : field = + (match label_decl.pld_mutable with + | Mutable -> unsupported label_decl + | _ -> ()); + (label_decl.pld_name.txt, Type.of_ocaml label_decl.pld_type) + + let of_ocaml : label_declaration list -> t = List.map ~f:field_of_ocaml +end + +(** Describe what is a variant payload, reflects OCaml's `construtor_arguments`. *) +module VariantPayload = struct + type t = Record of Record.t | Tuple of Type.t list | None + [@@deriving show, yojson] + + open Ppxlib + + let of_ocaml (cons_decl : constructor_arguments) : t = + match cons_decl with + | Pcstr_tuple [] -> None + | Pcstr_tuple [ typ ] -> ( + match typ.ptyp_desc with + | Ptyp_tuple types -> Tuple (List.map ~f:Type.of_ocaml types) + | _ -> Tuple [ Type.of_ocaml typ ]) + | Pcstr_tuple types -> Tuple (List.map ~f:Type.of_ocaml types) + | Pcstr_record label_decls -> Record (Record.of_ocaml label_decls) +end + +(** Describe what is a variant, reflects OCaml's `constructor_declaration`. *) +module Variant = struct + type t = { name : string; payload : VariantPayload.t } + [@@deriving show, yojson] + + let unsupported v = raise (Error (UnsupportedConstructorDeclaration v)) + + open Ppxlib + + let of_ocaml (cons_decl : constructor_declaration) : t = + if List.is_empty cons_decl.pcd_vars |> not then unsupported cons_decl; + let payload = VariantPayload.of_ocaml cons_decl.pcd_args in + { name = cons_decl.pcd_name.txt; payload } +end + +(** A result type. *) +module Result = struct + type ('r, 'e) t = Ok of 'r | Error of 'e [@@deriving show, yojson] +end + +(** Describe what is a datatype, reflects ppx' `type_declaration`. *) +module Datatype = struct + type kind = + | Record of Record.t + | Variant of Variant.t list + | TypeSynonym of Type.t + | Opaque + (** `Opaque` is not produced by `of_ocaml` below; it is used by `codegen_visitor` to generate identity visitors *) + [@@deriving show, yojson] + + type t = { name : string; type_vars : string list; kind : kind } + [@@deriving show, yojson] + + let unsupported v = raise (Error (UnsupportedTypeDeclaration v)) + + let of_ocaml (type_decl : Ppxlib.type_declaration) : t = + let open Ppxlib in + let name = type_decl.ptype_name.txt in + let type_vars = + List.map + ~f:(fun (t, _) -> + match t.ptyp_desc with + | Ptyp_var n -> "'" ^ n + | _ -> unsupported type_decl) + type_decl.ptype_params + in + if List.is_empty type_decl.ptype_cstrs |> not then unsupported type_decl; + let kind = + match (type_decl.ptype_kind, type_decl.ptype_manifest) with + | Ptype_abstract, Some typ -> TypeSynonym (Type.of_ocaml typ) + | Ptype_variant cons_decls, None -> + Variant (List.map ~f:Variant.of_ocaml cons_decls) + | Ptype_record label_decls, None -> Record (Record.of_ocaml label_decls) + | _ -> unsupported type_decl + in + { name; kind; type_vars } + + let of_ocaml_result (type_decl : Ppxlib.type_declaration) : + (t, Errors.t) Result.t = + try Result.Ok (of_ocaml type_decl) with Errors.Error e -> Result.Error e +end diff --git a/engine/utils/generate_visitors/utils.ml b/engine/utils/generate_visitors/utils.ml new file mode 100644 index 000000000..c5c3604e4 --- /dev/null +++ b/engine/utils/generate_visitors/utils.ml @@ -0,0 +1,35 @@ +open Base +include Ppx_yojson_conv_lib.Yojson_conv.Primitives + +let ( >> ) f g x = g (f x) + +let type_declaration_of_structure (str : Ppxlib.structure) : + (string * Ppxlib.type_declaration) list = + let open Ppxlib in + let visitor = + object (self) + inherit Ast_traverse.iter as super + val mutable result = [] + val mutable path_state = [] + + method get_path () = + List.rev path_state |> List.map ~f:(Option.value ~default:"") + + method get_result () = List.rev result + + method! module_binding mb = + let prev_path = path_state in + path_state <- mb.pmb_name.txt :: path_state; + super#module_binding mb; + path_state <- prev_path; + () + + method! type_declaration decl = + let path = + self#get_path () @ [ decl.ptype_name.txt ] |> String.concat ~sep:"." + in + result <- (path, decl) :: result + end + in + visitor#structure str; + visitor#get_result () diff --git a/engine/utils/generate_visitors/visitors.ml b/engine/utils/generate_visitors/visitors.ml new file mode 100644 index 000000000..eb67edc91 --- /dev/null +++ b/engine/utils/generate_visitors/visitors.ml @@ -0,0 +1,184 @@ +(** This module is mostly generated, but hand-edited, it defines +visitors for the types defined in module `Types`. *) + +open Base +open Types +open Utils + +class virtual ['self] reduce = + object (self : 'self) + method virtual plus : 'acc -> 'acc -> 'acc + method virtual zero : 'acc + method visit_string (_env : 'env) (_s : string) = self#zero + + method visit_prim___tuple_2 + : 't0 't1. + ('env -> 't0 -> 'acc) -> + ('env -> 't1 -> 'acc) -> + 'env -> + 't0 * 't1 -> + 'acc = + fun visit_'t0 visit_'t1 env___var v___payload -> + match v___payload with + | x0, x1 -> + let a0 = visit_'t0 env___var x0 in + let a1 = visit_'t1 env___var x1 in + self#plus a0 a1 + + method visit_prim___tuple_3 + : 't0 't1 't2. + ('env -> 't0 -> 'acc) -> + ('env -> 't1 -> 'acc) -> + ('env -> 't2 -> 'acc) -> + 'env -> + 't0 * 't1 * 't2 -> + 'acc = + fun visit_'t0 visit_'t1 visit_'t2 env___var v___payload -> + match v___payload with + | x0, x1, x2 -> + let a0 = visit_'t0 env___var x0 in + let a1 = visit_'t1 env___var x1 in + let a2 = visit_'t2 env___var x2 in + self#plus (self#plus a0 a1) a2 + + method visit_prim___tuple_4 + : 't0 't1 't2 't3. + ('env -> 't0 -> 'acc) -> + ('env -> 't1 -> 'acc) -> + ('env -> 't2 -> 'acc) -> + ('env -> 't3 -> 'acc) -> + 'env -> + 't0 * 't1 * 't2 * 't3 -> + 'acc = + fun visit_'t0 visit_'t1 visit_'t2 visit_'t3 env___var v___payload -> + match v___payload with + | x0, x1, x2, x3 -> + let a0 = visit_'t0 env___var x0 in + let a1 = visit_'t1 env___var x1 in + let a2 = visit_'t2 env___var x2 in + let a3 = visit_'t3 env___var x3 in + self#plus (self#plus (self#plus a0 a1) a2) a3 + + method visit_option : 'a. ('env -> 'a -> 'acc) -> 'env -> 'a option -> 'acc + = + fun visit_'a env___var v___payload -> + match v___payload with + | Some x0 -> + let a0 = visit_'a env___var x0 in + a0 + | None -> self#zero + + method visit_Type__t : 'env -> Type.t -> 'acc = + fun env___var v___payload -> + let acc___typ = self#visit_string env___var v___payload.typ in + let acc___args = + self#visit_list self#visit_Type__t env___var v___payload.args + in + self#plus acc___typ acc___args + + method visit_Record__field : 'env -> Record.field -> 'acc = + fun env___var v___payload -> + self#visit_prim___tuple_2 self#visit_string self#visit_Type__t env___var + v___payload + + method visit_Record__t : 'env -> Record.t -> 'acc = + fun env___var v___payload -> + self#visit_list self#visit_Record__field env___var v___payload + + method visit_VariantPayload__t : 'env -> VariantPayload.t -> 'acc = + fun env___var v___payload -> + match v___payload with + | Record x0 -> + let a0 = self#visit_Record__t env___var x0 in + a0 + | Tuple x0 -> + let a0 = self#visit_list self#visit_Type__t env___var x0 in + a0 + | None -> self#zero + + method visit_Variant__t : 'env -> Variant.t -> 'acc = + fun env___var v___payload -> + let acc___name = self#visit_string env___var v___payload.name in + let acc___payload = + self#visit_VariantPayload__t env___var v___payload.payload + in + self#plus acc___name acc___payload + + method visit_Result__t + : 'r 'e. + ('env -> 'r -> 'acc) -> + ('env -> 'e -> 'acc) -> + 'env -> + ('r, 'e) Result.t -> + 'acc = + fun visit_'r visit_'e env___var v___payload -> + match v___payload with + | Ok x0 -> + let a0 = visit_'r env___var x0 in + a0 + | Error x0 -> + let a0 = visit_'e env___var x0 in + a0 + + method visit_Datatype__kind : 'env -> Datatype.kind -> 'acc = + fun env___var v___payload -> + match v___payload with + | Record x0 -> + let a0 = self#visit_Record__t env___var x0 in + a0 + | Variant x0 -> + let a0 = self#visit_list self#visit_Variant__t env___var x0 in + a0 + | TypeSynonym x0 -> + let a0 = self#visit_Type__t env___var x0 in + a0 + | Opaque -> self#zero + + method visit_Datatype__t : 'env -> Datatype.t -> 'acc = + fun env___var v___payload -> + let acc___name = self#visit_string env___var v___payload.name in + let acc___type_vars = + self#visit_list self#visit_string env___var v___payload.type_vars + in + let acc___kind = self#visit_Datatype__kind env___var v___payload.kind in + self#plus (self#plus acc___name acc___type_vars) acc___kind + + method visit_datatypes : 'env -> Datatype.t list -> 'acc = + self#visit_list self#visit_Datatype__t + + method visit_list : 'a. ('env -> 'a -> 'acc) -> 'env -> 'a list -> 'acc = + fun v env this -> + Base.List.fold ~init:self#zero + ~f:(fun acc -> v env >> self#plus acc) + this + end + +let collect_defined_types = + (object + inherit [_] reduce as _super + method plus = Set.union + method zero = Set.empty (module String) + method! visit_Datatype__t () dt = Set.singleton (module String) dt.name + end) + #visit_datatypes + () + +let collect_used_types = + (object (self) + inherit [_] reduce as super + method plus = Set.union + method zero = Set.empty (module String) + + method! visit_Type__t () t = + let typ = t.typ in + self#plus + (if String.is_prefix ~prefix:"'" typ || String.equal typ "list" then + self#zero + else Set.singleton (module String) typ) + (super#visit_Type__t () t) + end) + #visit_datatypes + () + +let collect_undefined_types dts : string list = + Set.diff (collect_used_types dts) (collect_defined_types dts) |> Set.to_list diff --git a/engine/utils/ocaml_of_json_schema/ocaml_of_json_schema.js b/engine/utils/ocaml_of_json_schema/ocaml_of_json_schema.js index 13e3b94c9..f3de435db 100644 --- a/engine/utils/ocaml_of_json_schema/ocaml_of_json_schema.js +++ b/engine/utils/ocaml_of_json_schema/ocaml_of_json_schema.js @@ -76,7 +76,16 @@ let variantNameOf = s => { }; let typeNameOf = s => s.replace(/[A-Z]/g, (l, i) => `${i?'_':''}${l.toLowerCase()}`); let fieldNameOf = s => { - if (['then', 'if', 'end', 'open', 'include', 'begin', 'fun', 'initializer'].includes(s)) + let ocaml_keywords = [ "and", "as", "assert", "asr", "begin", "class", "constraint", + "do", "done", "downto", "else", "end", "exception", "external", + "false", "for", "fun", "function", "functor", "if", "in", + "include", "inherit", "initializer", "land", "lazy", "let", + "lor", "lsl", "lsr", "lxor", "match", "method", "mod", "module", + "mutable", "new", "nonrec", "object", "of", "open", "or", + "private", "rec", "sig", "struct", "then", "to", "true", "try", + "type", "val", "virtual", "when", "while", "with" + ]; + if (ocaml_keywords.includes(s)) return s + "'"; return s; }; diff --git a/engine/utils/ppx_functor_application/README.md b/engine/utils/ppx_functor_application/README.md index fb852d344..3a59a7558 100644 --- a/engine/utils/ppx_functor_application/README.md +++ b/engine/utils/ppx_functor_application/README.md @@ -1,65 +1,82 @@ -# `ppx_inline` +# `ppx_functor_application` -Inlines chunks of OCaml AST in place. +## Motivation +The engine consists of numerous phases, implemented as OCaml functors +parametrized over "AST features" (see the book). Two phases can be +binded (sequenced) via `Phase_utils.BindPhase` functor. -Rewrite `[%%inline_defs L]`, `[%%inline_arms L]`, `[%%inline_body PATH]` inside nodes `[%%inlined_contents NODE]`, where: - - `L` is a (`+`/`-`-separated) list of path specifying which chunk of AST we should inline; - - `PATH` is a `.`-separated list of strings, possibly containing the `*` glob. +Since OCaml define (or let users define) infix notations for functor +application, combining many phases (functors) results in the following +christmas tree looking kinds of code: -## Example: -File `some_module.ml`: ```ocaml -let f x = x + 1 -let g x = x + 2 -let f' x = x + 3 - -module M = struct - let w = 0 - let x = 1 - let y = 2 - let z = 3 +struct + module ARG0 = (Phases.Reject.RawOrMutPointer)(Features.Rust) + module ARG1 = (Phases.Transform_hax_lib_inline)(ARG0.FB) + module ARG2 = (Phases.Specialize)(ARG1.FB) + module ARG3 = (Phases.Drop_sized_trait)(ARG2.FB) + module ARG4 = (Phases.Simplify_question_marks)(ARG3.FB) + module ARG5 = (Phases.And_mut_defsite)(ARG4.FB) + module ARG6 = (Phases.Reconstruct_for_loops)(ARG5.FB) + module ARG7 = (Phases.Reconstruct_while_loops)(ARG6.FB) + module ARG8 = (Phases.Direct_and_mut)(ARG7.FB) + module ARG9 = (Phases.Reject.Arbitrary_lhs)(ARG8.FB) + module ARG10 = (Phases.Drop_blocks)(ARG9.FB) + module ARG11 = (Phases.Drop_references)(ARG10.FB) + module ARG12 = (Phases.Trivialize_assign_lhs)(ARG11.FB) + module ARG13 = (Side_effect_utils.Hoist)(ARG12.FB) + module ARG14 = (Phases.Simplify_match_return)(ARG13.FB) + module ARG15 = (Phases.Drop_needless_returns)(ARG14.FB) + module ARG16 = (Phases.Local_mutation)(ARG15.FB) + module ARG17 = (Phases.Reject.Continue)(ARG16.FB) + module ARG18 = (Phases.Cf_into_monads)(ARG17.FB) + module ARG19 = (Phases.Reject.EarlyExit)(ARG18.FB) + module ARG20 = (Phases.Functionalize_loops)(ARG19.FB) + module ARG21 = (Phases.Reject.As_pattern)(ARG20.FB) + module ARG22 = (Phases.Traits_specs)(ARG21.FB) + module ARG23 = (Phases.Simplify_hoisting)(ARG22.FB) + module ARG24 = (Phases.Newtype_as_refinement)(ARG23.FB) + module ARG25 = (SubtypeToInputLanguage)(ARG24.FB) + module ARG26 = (Identity)(ARG25.FB) + include + ((BindPhase)(((BindPhase)(((BindPhase)(((BindPhase)(((BindPhase)(((BindPhase)(((BindPhase)(((BindPhase)(((BindPhase)(((BindPhase)(((BindPhase)(((BindPhase)(((BindPhase)(((BindPhase)(((BindPhase)(((BindPhase)(((BindPhase)(((BindPhase)(((BindPhase)(((BindPhase)(((BindPhase)(((BindPhase)(((BindPhase)(((BindPhase)(((BindPhase)(((BindPhase)(ARG0))(ARG1)))(ARG2)))(ARG3)))(ARG4)))(ARG5)))(ARG6)))(ARG7)))(ARG8)))(ARG9)))(ARG10)))(ARG11)))(ARG12)))(ARG13)))(ARG14)))(ARG15)))(ARG16)))(ARG17)))(ARG18)))(ARG19)))(ARG20)))(ARG21)))(ARG22)))(ARG23)))(ARG24)))(ARG25)))(ARG26) end - -let h x = "" -type foo = | A | B -let i (x: foo) = - match x with - | A -> 0 - | B -> 1 ``` -The module: -```ocaml -module%inlined_contents [@@add "some_module.ml"] Test = struct - [%%inline_defs f + g + foo] - [%%inline_defs "M.*" - z - y] - - let h: int -> string = [%%inline_body h] - let i: foo -> int = - match i with - | [%%inline_arms "i.*" - B] -> dummy - | B -> 123 -end -``` +The system of phases is supposed to let backends opt-in or out easily +for phases. This syntactic limitation was a major issue for that. + +## Solution +This PPX defines a small DSL that embeds in the OCaml syntax of +expressions to provide a nice way of binding phases functors via a +`|>` infix operator. -Will be rewritten into: +Example: ```ocaml -module%inlined_contents [@@add "some_module.ml"] Test = struct - - (* [%%inline_defs f + g + foo] *) - let f x = x + 1 - let g x = x + 2 - type foo = | A | B - - (* [%%inline_defs "M.*" - z - y] *) - let w = 0 - let x = 1 - - let h: int -> string = (fun x -> "") - let i: foo -> int = - match i with - | A -> 0 - | B -> 123 -end +module TransformToInputLanguage = + [%functor_application + Phases.Reject.RawOrMutPointer(Features.Rust) + |> Phases.Transform_hax_lib_inline + |> Phases.Specialize + |> Phases.Drop_sized_trait + |> Phases.Simplify_question_marks + |> Phases.And_mut_defsite + |> Phases.Reconstruct_for_loops + |> Phases.Reconstruct_while_loops + |> SubtypeToInputLanguage + |> Identity + ] + [@ocamlformat "disable"] ``` +Note: the `[@ocamlformat "disable"]` annotation is important, +otherwise `ocamlformat` tries to format those PPX invokations with its +rules for expressions, yielding rather ugly looking code... + +### Syntax + - `Name`: a module `Name` + - `Name(X, Y, Z)`: the application of the functor `Name` with three arguments `X`, `Y` and `Z` + - `(module )`: the arbitary OCaml module expression `` + - ` `: the application of the module described by `` and the module described by `` + - `(fun X -> )`: a "functor" from `X` to `` + - ` |> `: `` binded with `` diff --git a/engine/utils/ppx_functor_application/ppx_functor_application.ml b/engine/utils/ppx_functor_application/ppx_functor_application.ml index c49ff7bd9..f53344de7 100644 --- a/engine/utils/ppx_functor_application/ppx_functor_application.ml +++ b/engine/utils/ppx_functor_application/ppx_functor_application.ml @@ -30,6 +30,7 @@ let show_module_expr = string_of_module_expr let pp_module_expr (fmt : Format.formatter) (s : module_expr) : unit = Format.pp_print_string fmt @@ string_of_module_expr s +(** Defines a DSL for functor application. *) type module_dsl = | Var of longident | App of module_dsl * module_dsl @@ -41,6 +42,7 @@ type module_dsl = let var_of_string s = Var (Longident.Lident s) +(** Elaborate a OCaml module expression from a `module_dsl` *) let rec elab ~loc (t : module_dsl) : module_expr = let (module E) = Ast_builder.make loc in let h = elab ~loc in @@ -92,6 +94,7 @@ let rec collect_pipes (t : module_dsl) : module_dsl list = | Meta (Pipe l, _) | Pipe l -> List.concat_map ~f:collect_pipes l | _ -> [ t ] +(** Get rid of extra `Pipe` nodes *) let rec normalize (t : module_dsl) : module_dsl = match t with | App (f, x) -> App (normalize f, normalize x) @@ -104,16 +107,28 @@ let rec normalize (t : module_dsl) : module_dsl = | [ t ] -> t | l -> Pipe l) +(** Recognize a small language embedded in OCaml syntax for applying +functors in chain. *) let rec parse expr = let r = match expr with - | { pexp_desc = Pexp_construct ({ txt; _ }, None); _ } -> Var txt + | { pexp_desc = Pexp_construct ({ txt; _ }, None); _ } -> + (* Parses variables (module names are uppercase, since we are looking at OCaml expressions, so we match on constructors) *) + Var txt | { pexp_desc = Pexp_construct ({ txt; _ }, Some arg); _ } -> + (* Parses module applcations (same as above: in expressions, module applications are parsed as constructor applications) *) App (Var txt, parse arg) - | [%expr [%e? m1] |> [%e? m2]] -> Pipe [ parse m1; parse m2 ] - | [%expr (module [%m? m])] -> ModExpr m - | [%expr [%e? f] [%e? x]] -> App (parse f, parse x) + | [%expr [%e? m1] |> [%e? m2]] -> + (* Parses `... |> ...` infix module application *) + Pipe [ parse m1; parse m2 ] + | [%expr (module [%m? m])] -> + (* Parses module expressions (in this case, that corresponds to OCaml module expression) *) + ModExpr m + | [%expr [%e? f] [%e? x]] -> + (* Parses module applications (e.g. `(fun x -> ...) (module YXZ)`) *) + App (parse f, parse x) | [%expr fun [%p? x] -> [%e? body]] -> ( + (* Parses module abstractions (e.g. `fun X -> Z(X)`) *) match x with | { ppat_desc = Ppat_construct ({ txt = Lident x; _ }, None); _ } -> Abs (x, parse body) diff --git a/flake.lock b/flake.lock index ad39d86a8..ba2824fa7 100644 --- a/flake.lock +++ b/flake.lock @@ -105,19 +105,16 @@ }, "rust-overlay": { "inputs": { - "flake-utils": [ - "flake-utils" - ], "nixpkgs": [ "nixpkgs" ] }, "locked": { - "lastModified": 1717381101, - "narHash": "sha256-TcM4+oHTSLw8neTxk/Q0beODr8YiL+oI2j0ENYnNfk4=", + "lastModified": 1723429325, + "narHash": "sha256-4x/32xTCd+xCwFoI/kKSiCr5LQA2ZlyTRYXKEni5HR8=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "07098b424d114cd2dddec40be8d5586da339fddc", + "rev": "65e3dc0fe079fe8df087cd38f1fe6836a0373aad", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index b85e532e6..19791054d 100644 --- a/flake.nix +++ b/flake.nix @@ -10,7 +10,6 @@ }; rust-overlay = { url = "github:oxalica/rust-overlay"; - inputs.flake-utils.follows = "flake-utils"; inputs.nixpkgs.follows = "nixpkgs"; }; fstar = { @@ -60,6 +59,7 @@ in rec { packages = { inherit rustc ocamlformat rustfmt fstar hax-env; + hax-book = pkgs.callPackage ./book {}; hax-engine = pkgs.callPackage ./engine { hax-rust-frontend = packages.hax-rust-frontend.unwrapped; # `hax-engine-names-extract` extracts Rust names but also @@ -85,6 +85,15 @@ check-toolchain = checks.toolchain; check-examples = checks.examples; check-readme-coherency = checks.readme-coherency; + + # The commit that corresponds to our nightly pin, helpful when updating rusrc. + toolchain_commit = pkgs.runCommand "hax-toolchain-commit" { } '' + # This is sad but I don't know a better way. + cat ${rustc}/share/doc/rust/html/version_info.html \ + | grep 'github.com' \ + | sed 's#.*"https://github.com/rust-lang/rust/commit/\([^"]*\)".*#\1#' \ + > $out + ''; }; checks = { toolchain = packages.hax.tests; @@ -119,7 +128,14 @@ type = "app"; program = "${pkgs.writeScript "serve-rustc-docs" '' cd ${packages.rustc.passthru.availableComponents.rustc-docs}/share/doc/rust/html/rustc - ${pkgs.python3}/bin/python -m http.server + ${pkgs.python3}/bin/python -m http.server "$@" + ''}"; + }; + serve-book = { + type = "app"; + program = "${pkgs.writeScript "serve-book" '' + cd ${packages.hax-book} + ${pkgs.python3}/bin/python -m http.server "$@" ''}"; }; }; @@ -136,6 +152,15 @@ }) ]; in let + utils = pkgs.stdenv.mkDerivation { + name = "hax-dev-scripts"; + phases = ["installPhase"]; + installPhase = '' + mkdir -p $out/bin + cp ${./.utils/rebuild.sh} $out/bin/rebuild + cp ${./.utils/list-names.sh} $out/bin/list-names + ''; + }; packages = [ ocamlformat pkgs.ocamlPackages.ocaml-lsp @@ -152,14 +177,7 @@ rustfmt rustc - (pkgs.stdenv.mkDerivation { - name = "rebuild-script"; - phases = ["installPhase"]; - installPhase = '' - mkdir -p $out/bin - cp ${./.utils/rebuild.sh} $out/bin/rebuild - ''; - }) + utils ]; LIBCLANG_PATH = "${pkgs.llvmPackages.libclang.lib}/lib"; in { @@ -175,6 +193,7 @@ }; default = pkgs.mkShell { inherit packages inputsFrom LIBCLANG_PATH; + shellHook = ''echo "Commands available: $(ls ${utils}/bin | tr '\n' ' ')"''; }; }; } diff --git a/frontend/diagnostics/Cargo.toml b/frontend/diagnostics/Cargo.toml deleted file mode 100644 index d506a5a64..000000000 --- a/frontend/diagnostics/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "hax-diagnostics" -version.workspace = true -authors.workspace = true -license.workspace = true -homepage.workspace = true -edition.workspace = true -repository.workspace = true -readme.workspace = true -description = "This crate defines types that represent the various errors that can occur in hax." - -[package.metadata.rust-analyzer] -rustc_private=true - -[dependencies] -serde.workspace = true -schemars.workspace = true -colored.workspace = true - diff --git a/frontend/diagnostics/src/error.rs b/frontend/diagnostics/src/error.rs deleted file mode 100644 index 477c6129f..000000000 --- a/frontend/diagnostics/src/error.rs +++ /dev/null @@ -1,195 +0,0 @@ -// rustc errors -extern crate rustc_errors; -use rustc_errors::DiagnosticId; - -// rustc session -extern crate rustc_session; -use rustc_session::Session; - -// rustc data_structures -extern crate rustc_data_structures; -use rustc_data_structures::sync::Lrc; - -// rustc span -extern crate rustc_span; -use rustc_span::Span; - -pub fn explicit_lifetime(session: &Lrc, span: Span) { - session.span_warn_with_code( - span, - "[Hax] Explicit lifetimes are not supported", - DiagnosticId::Lint { - name: "Lifetime".to_string(), - has_future_breakage: false, - is_force_warn: true, - }, - ); -} - -pub fn mut_borrow_let(session: &Lrc, span: Span) { - session.span_warn_with_code( - span, - "[Hax] Mutable borrows are not supported", - DiagnosticId::Lint { - name: "Mut borrow".to_string(), - has_future_breakage: false, - is_force_warn: true, - }, - ); -} - -pub fn extern_crate(session: &Lrc, span: Span) { - session.span_warn_with_code( - span, - "[Hax] External items need a model", - DiagnosticId::Lint { - name: "External".to_string(), - has_future_breakage: false, - is_force_warn: true, - }, - ); -} - -pub fn no_trait_objects(session: &Lrc, span: Span) { - session.span_warn_with_code( - span, - "[Hax] Trait objects are not supported", - DiagnosticId::Lint { - name: "Trait objects".to_string(), - has_future_breakage: false, - is_force_warn: true, - }, - ); -} - -pub fn no_mut_self(session: &Lrc, span: Span) { - session.span_warn_with_code( - span, - "[Hax] Mutable self is not supported", - DiagnosticId::Lint { - name: "Mutable self".to_string(), - has_future_breakage: false, - is_force_warn: true, - }, - ); -} - -pub fn no_mut(session: &Lrc, span: Span) { - session.span_warn_with_code( - span, - "[Hax] Mutable arguments are not supported", - DiagnosticId::Lint { - name: "Mutability".to_string(), - has_future_breakage: false, - is_force_warn: true, - }, - ); -} - -pub fn no_assoc_items(session: &Lrc, span: Span) { - session.span_warn_with_code( - span, - "[Hax] Associated items are not supported", - DiagnosticId::Lint { - name: "Assoc items".to_string(), - has_future_breakage: false, - is_force_warn: true, - }, - ); -} - -pub fn unsupported_item(session: &Lrc, span: Span, ident: String) { - session.span_warn_with_code( - span, - format!("[Hax] {ident:?} is not supported"), - DiagnosticId::Lint { - name: "Unsupported item".to_string(), - has_future_breakage: false, - is_force_warn: true, - }, - ); -} - -pub fn no_fn_mut(session: &Lrc, span: Span) { - session.span_warn_with_code( - span, - "[Hax] FnMut is not supported", - DiagnosticId::Lint { - name: "Where".to_string(), - has_future_breakage: false, - is_force_warn: true, - }, - ); -} - -pub fn no_where_predicate(session: &Lrc, span: Span) { - session.span_warn_with_code( - span, - "[Hax] Where predicates are not supported", - DiagnosticId::Lint { - name: "Where".to_string(), - has_future_breakage: false, - is_force_warn: true, - }, - ); -} - -pub fn no_async_await(session: &Lrc, span: Span) { - session.span_warn_with_code( - span, - "[Hax] Async and await are not supported", - DiagnosticId::Lint { - name: "Async".to_string(), - has_future_breakage: false, - is_force_warn: true, - }, - ); -} - -pub fn no_unsafe(session: &Lrc, span: Span) { - session.span_warn_with_code( - span, - "[Hax] Unsafe code is not supported", - DiagnosticId::Lint { - name: "Unsafe".to_string(), - has_future_breakage: false, - is_force_warn: true, - }, - ); -} - -pub fn unsupported_loop(session: &Lrc, span: Span) { - session.span_warn_with_code( - span, - "[Hax] loop and while are not supported", - DiagnosticId::Lint { - name: "Loops".to_string(), - has_future_breakage: false, - is_force_warn: true, - }, - ); -} - -pub fn no_union(session: &Lrc, span: Span) { - session.span_warn_with_code( - span, - "[Hax] Unions are not supported", - DiagnosticId::Lint { - name: "Unsupported item".to_string(), - has_future_breakage: false, - is_force_warn: true, - }, - ); -} - -pub fn derive_external_trait(session: &Lrc, span: Span, trait_name: String) { - session.span_warn_with_code( - span, - format!("[Hax] Implementation of external trait {trait_name} will require a model"), - DiagnosticId::Lint { - name: "External trait".to_string(), - has_future_breakage: false, - is_force_warn: true, - }, - ); -} diff --git a/frontend/exporter/Cargo.toml b/frontend/exporter/Cargo.toml index 3ac731416..a9ed2b247 100644 --- a/frontend/exporter/Cargo.toml +++ b/frontend/exporter/Cargo.toml @@ -23,3 +23,12 @@ tracing.workspace = true paste = "1.0.11" extension-traits = "1.0.1" lazy_static = "1.4.0" +bincode.workspace = true + +[features] +default = ["rustc"] +extract_names_mode = [] +# Enables the conversion bridges from rustc types (and AST) to the +# ones defined in this crate. Enabling `rustc` adds a dependency to +# `librustc_driver`. +rustc = [] diff --git a/frontend/exporter/adt-into/src/lib.rs b/frontend/exporter/adt-into/src/lib.rs index 28628646f..2d0a115f5 100644 --- a/frontend/exporter/adt-into/src/lib.rs +++ b/frontend/exporter/adt-into/src/lib.rs @@ -384,13 +384,14 @@ pub fn adt_into(input: proc_macro::TokenStream) -> proc_macro::TokenStream { }; quote! { + #[cfg(feature = "rustc")] const _ : () = { use #from as FROM_TYPE; use #to as TO_TYPE; impl #generics SInto<#state_type, #to #to_generics> for #from_with_generics { #[tracing::instrument(level = "trace", skip(#state))] fn sinto(&self, #state: &#state_type) -> #to #to_generics { - tracing::trace!("Enters sinto"); + tracing::trace!("Enters sinto ({})", stringify!(#from_with_generics)); #body } } @@ -437,3 +438,41 @@ fn drop_generics(type_path: syn::TypePath) -> syn::TypePath { ..type_path } } + +/// A proc macro unrelated to `adt-into`: it is useful in hax +/// and we don't want a whole crate only for that helper. +/// +/// This proc macro defines some groups of derive clauses that +/// we reuse all the time. This is particularly interesting for +/// serializers and deserializers: today we use `bincode` and +/// `serde`, but maybe we will want to move to something else +/// in the future. +#[proc_macro_attribute] +pub fn derive_group( + attr: proc_macro::TokenStream, + item: proc_macro::TokenStream, +) -> proc_macro::TokenStream { + let item: proc_macro2::TokenStream = item.into(); + let groups = format!("{attr}"); + let groups = groups.split(",").map(|s| s.trim()); + let mut errors = vec![]; + let result: proc_macro2::TokenStream = groups + .map(|group| match group { + "Serializers" => quote! { + #[derive(::serde::Serialize, ::serde::Deserialize)] + #[derive(::bincode::Encode, ::bincode::Decode)] + }, + _ => { + errors.push(quote! { + const _: () = compile_error!(concat!( + "derive_group: `", + stringify!(#group), + "` is not a recognized group name" + )); + }); + quote! {} + } + }) + .collect(); + quote! {#(#errors)* #result #item}.into() +} diff --git a/frontend/exporter/options/Cargo.toml b/frontend/exporter/options/Cargo.toml index fadcbc905..a8f04c553 100644 --- a/frontend/exporter/options/Cargo.toml +++ b/frontend/exporter/options/Cargo.toml @@ -13,4 +13,5 @@ description = "The options the `hax-frontend-exporter` crate is sensible to." serde.workspace = true serde_json.workspace = true schemars.workspace = true - +hax-adt-into.workspace = true +bincode.workspace = true diff --git a/frontend/exporter/options/src/lib.rs b/frontend/exporter/options/src/lib.rs index a19c79f70..1accf3d9e 100644 --- a/frontend/exporter/options/src/lib.rs +++ b/frontend/exporter/options/src/lib.rs @@ -1,13 +1,15 @@ +use hax_adt_into::derive_group; use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; -#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Debug, Clone, JsonSchema)] pub enum Glob { One, // * Many, // ** } -#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Debug, Clone, JsonSchema)] pub enum NamespaceChunk { Glob(Glob), Exact(String), @@ -23,7 +25,8 @@ impl std::convert::From<&str> for NamespaceChunk { } } -#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Debug, Clone, JsonSchema)] pub struct Namespace { pub chunks: Vec, } diff --git a/frontend/exporter/src/body.rs b/frontend/exporter/src/body.rs index 89cb57c89..99fcd3b5b 100644 --- a/frontend/exporter/src/body.rs +++ b/frontend/exporter/src/body.rs @@ -1,99 +1,109 @@ -use crate::prelude::*; +pub use module::*; -pub use rustc_hir::{ - def_id::{DefId as RDefId, LocalDefId as RLocalDefId}, - hir_id::OwnerId as ROwnerId, -}; - -pub fn get_thir<'tcx, S: UnderOwnerState<'tcx>>( - did: RLocalDefId, - s: &S, -) -> ( - Rc>, - rustc_middle::thir::ExprId, -) { - let base = s.base(); - let msg = || fatal!(s[base.tcx.def_span(did)], "THIR not found for {:?}", did); - base.cached_thirs.get(&did).unwrap_or_else(msg).clone() +#[cfg(not(feature = "rustc"))] +mod module { + pub trait IsBody: Sized + Clone + 'static {} + impl IsBody for T {} } -pub trait IsBody: Sized + Clone { - fn body<'tcx, S: UnderOwnerState<'tcx>>(did: RLocalDefId, s: &S) -> Self; -} +#[cfg(feature = "rustc")] +mod module { + pub use crate::prelude::*; + pub use rustc_hir::{ + def_id::{DefId as RDefId, LocalDefId as RLocalDefId}, + hir_id::OwnerId as ROwnerId, + }; -pub fn make_fn_def<'tcx, Body: IsBody, S: UnderOwnerState<'tcx>>( - fn_sig: &rustc_hir::FnSig, - body_id: &rustc_hir::BodyId, - s: &S, -) -> FnDef { - let hir_id = body_id.hir_id; - let ldid = hir_id.clone().owner.def_id; + pub fn get_thir<'tcx, S: UnderOwnerState<'tcx>>( + did: RLocalDefId, + s: &S, + ) -> ( + Rc>, + rustc_middle::thir::ExprId, + ) { + let base = s.base(); + let msg = || fatal!(s[base.tcx.def_span(did)], "THIR not found for {:?}", did); + base.cached_thirs.get(&did).unwrap_or_else(msg).clone() + } - let (thir, expr_entrypoint) = get_thir(ldid, s); - let s = &with_owner_id(s.base(), thir.clone(), (), ldid.to_def_id()); - FnDef { - params: thir.params.raw.sinto(s), - ret: thir.exprs[expr_entrypoint].ty.sinto(s), - body: Body::body(ldid, s), - sig_span: fn_sig.span.sinto(s), - header: fn_sig.header.sinto(s), + pub trait IsBody: Sized + Clone + 'static { + fn body<'tcx, S: UnderOwnerState<'tcx>>(did: RLocalDefId, s: &S) -> Self; } -} -pub fn body_from_id<'tcx, Body: IsBody, S: UnderOwnerState<'tcx>>( - id: rustc_hir::BodyId, - s: &S, -) -> Body { - // **Important:** - // We need a local id here, and we get it from the owner id, which must - // be local. It is safe to do so, because if we have access to HIR objects, - // it necessarily means we are exploring a local item (we don't have - // access to the HIR of external objects, only their MIR). - Body::body(s.base().tcx.hir().body_owner_def_id(id), s) -} + pub fn make_fn_def<'tcx, Body: IsBody, S: UnderOwnerState<'tcx>>( + fn_sig: &rustc_hir::FnSig, + body_id: &rustc_hir::BodyId, + s: &S, + ) -> FnDef { + let hir_id = body_id.hir_id; + let ldid = hir_id.clone().owner.def_id; -mod implementations { - use super::*; - impl IsBody for () { - fn body<'tcx, S: UnderOwnerState<'tcx>>(_did: RLocalDefId, _s: &S) -> Self { - () + let (thir, expr_entrypoint) = get_thir(ldid, s); + let s = &with_owner_id(s.base(), thir.clone(), (), ldid.to_def_id()); + FnDef { + params: thir.params.raw.sinto(s), + ret: thir.exprs[expr_entrypoint].ty.sinto(s), + body: Body::body(ldid, s), + sig_span: fn_sig.span.sinto(s), + header: fn_sig.header.sinto(s), } } - impl IsBody for ThirBody { - fn body<'tcx, S: UnderOwnerState<'tcx>>(did: RLocalDefId, s: &S) -> Self { - let (thir, expr) = get_thir(did, s); - if *CORE_EXTRACTION_MODE { - let expr = &thir.exprs[expr.clone()]; - Decorated { - contents: Box::new(ExprKind::Tuple { fields: vec![] }), - hir_id: None, - attributes: vec![], - ty: expr.ty.sinto(s), - span: expr.span.sinto(s), + + pub fn body_from_id<'tcx, Body: IsBody, S: UnderOwnerState<'tcx>>( + id: rustc_hir::BodyId, + s: &S, + ) -> Body { + // **Important:** + // We need a local id here, and we get it from the owner id, which must + // be local. It is safe to do so, because if we have access to HIR objects, + // it necessarily means we are exploring a local item (we don't have + // access to the HIR of external objects, only their MIR). + Body::body(s.base().tcx.hir().body_owner_def_id(id), s) + } + + mod implementations { + use super::*; + impl IsBody for () { + fn body<'tcx, S: UnderOwnerState<'tcx>>(_did: RLocalDefId, _s: &S) -> Self { + () + } + } + impl IsBody for ThirBody { + fn body<'tcx, S: UnderOwnerState<'tcx>>(did: RLocalDefId, s: &S) -> Self { + let (thir, expr) = get_thir(did, s); + if *CORE_EXTRACTION_MODE { + let expr = &thir.exprs[expr.clone()]; + Decorated { + contents: Box::new(ExprKind::Tuple { fields: vec![] }), + hir_id: None, + attributes: vec![], + ty: expr.ty.sinto(s), + span: expr.span.sinto(s), + } + } else { + expr.sinto(&with_owner_id(s.base(), thir, (), did.to_def_id())) } - } else { - expr.sinto(&with_owner_id(s.base(), thir, (), did.to_def_id())) } } - } - impl IsBody for (A, B) { - fn body<'tcx, S: UnderOwnerState<'tcx>>(did: RLocalDefId, s: &S) -> Self { - (A::body(did, s), B::body(did, s)) + impl IsBody for (A, B) { + fn body<'tcx, S: UnderOwnerState<'tcx>>(did: RLocalDefId, s: &S) -> Self { + (A::body(did, s), B::body(did, s)) + } } - } - impl IsBody for MirBody { - fn body<'tcx, S: UnderOwnerState<'tcx>>(did: RLocalDefId, s: &S) -> Self { - let (thir, _) = get_thir(did, s); - let mir = Rc::new(s.base().tcx.mir_built(did).borrow().clone()); - mir.sinto(&with_owner_id(s.base(), thir, mir.clone(), did.to_def_id())) + impl IsBody for MirBody { + fn body<'tcx, S: UnderOwnerState<'tcx>>(did: RLocalDefId, s: &S) -> Self { + let (thir, _) = get_thir(did, s); + let mir = Rc::new(s.base().tcx.mir_built(did).borrow().clone()); + mir.sinto(&with_owner_id(s.base(), thir, mir.clone(), did.to_def_id())) + } } } -} -impl<'tcx, S: UnderOwnerState<'tcx>, Body: IsBody> SInto for rustc_hir::BodyId { - fn sinto(&self, s: &S) -> Body { - body_from_id::(self.clone(), s) + impl<'tcx, S: UnderOwnerState<'tcx>, Body: IsBody> SInto for rustc_hir::BodyId { + fn sinto(&self, s: &S) -> Body { + body_from_id::(self.clone(), s) + } } } diff --git a/frontend/exporter/src/constant_utils.rs b/frontend/exporter/src/constant_utils.rs index 6c99bb3d9..ef8b476ef 100644 --- a/frontend/exporter/src/constant_utils.rs +++ b/frontend/exporter/src/constant_utils.rs @@ -1,17 +1,24 @@ use crate::prelude::*; -use rustc_middle::{mir, ty}; -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum ConstantInt { - Int(i128, IntTy), - Uint(u128, UintTy), + Int( + #[serde(with = "serialize_int::signed")] + #[schemars(with = "String")] + i128, + IntTy, + ), + Uint( + #[serde(with = "serialize_int::unsigned")] + #[schemars(with = "String")] + u128, + UintTy, + ), } -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum ConstantLiteral { Bool(bool), Char(char), @@ -21,9 +28,8 @@ pub enum ConstantLiteral { } /// The subset of [Expr] that corresponds to constants. -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum ConstantExprKind { Literal(ConstantLiteral), Adt { @@ -86,167 +92,173 @@ pub enum ConstantExprKind { Todo(String), } -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct ConstantFieldExpr { pub field: DefId, pub value: ConstantExpr, } /// Rustc has different representation for constants: one for MIR -/// ([`rustc_middle::mir::ConstantKind`]), one for the type system +/// ([`rustc_middle::mir::Const`]), one for the type system /// ([`rustc_middle::ty::ConstKind`]). For simplicity hax maps those /// two construct to one same `ConstantExpr` type. pub type ConstantExpr = Decorated; -impl From for FieldExpr { - fn from(c: ConstantFieldExpr) -> FieldExpr { - FieldExpr { - value: c.value.into(), - field: c.field, +#[cfg(feature = "rustc")] +pub use self::rustc::*; +#[cfg(feature = "rustc")] +mod rustc { + use super::*; + use rustc_middle::{mir, ty}; + + impl From for FieldExpr { + fn from(c: ConstantFieldExpr) -> FieldExpr { + FieldExpr { + value: c.value.into(), + field: c.field, + } } } -} -impl ConstantLiteral { - /// Rustc always represents string constants as `&[u8]`, but this - /// is not nice to consume. This associated function interpret - /// bytes as an unicode string, and as a byte string otherwise. - fn byte_str(bytes: Vec, style: StrStyle) -> Self { - match String::from_utf8(bytes.clone()) { - Ok(s) => Self::Str(s, style), - Err(_) => Self::ByteStr(bytes, style), + impl ConstantLiteral { + /// Rustc always represents string constants as `&[u8]`, but this + /// is not nice to consume. This associated function interpret + /// bytes as an unicode string, and as a byte string otherwise. + fn byte_str(bytes: Vec, style: StrStyle) -> Self { + match String::from_utf8(bytes.clone()) { + Ok(s) => Self::Str(s, style), + Err(_) => Self::ByteStr(bytes, style), + } } } -} -impl From for Expr { - fn from(c: ConstantExpr) -> Expr { - use ConstantExprKind::*; - let kind = match *c.contents { - Literal(lit) => { - use ConstantLiteral::*; - let mut neg = false; - let node = match lit { - Bool(b) => LitKind::Bool(b), - Char(c) => LitKind::Char(c), - Int(i) => { - use LitIntType::*; - match i { - ConstantInt::Uint(v, t) => LitKind::Int(v, Unsigned(t)), - ConstantInt::Int(v, t) => { - neg = v.is_negative(); - LitKind::Int(v.abs_diff(0), Signed(t)) + impl From for Expr { + fn from(c: ConstantExpr) -> Expr { + use ConstantExprKind::*; + let kind = match *c.contents { + Literal(lit) => { + use ConstantLiteral::*; + let mut neg = false; + let node = match lit { + Bool(b) => LitKind::Bool(b), + Char(c) => LitKind::Char(c), + Int(i) => { + use LitIntType::*; + match i { + ConstantInt::Uint(v, t) => LitKind::Int(v, Unsigned(t)), + ConstantInt::Int(v, t) => { + neg = v.is_negative(); + LitKind::Int(v.abs_diff(0), Signed(t)) + } } } - } - ByteStr(raw, str_style) => LitKind::ByteStr(raw, str_style), - Str(raw, str_style) => LitKind::Str(raw, str_style), - }; - let span = c.span.clone(); - let lit = Spanned { span, node }; - ExprKind::Literal { lit, neg } - } - Adt { info, fields } => ExprKind::Adt(AdtExpr { - info, - fields: fields.into_iter().map(|field| field.into()).collect(), - base: None, - user_ty: None, - }), - // TODO: propagate the generics and trait refs (see #636) - GlobalName { - id, - generics: _, - trait_refs: _, - } => ExprKind::GlobalName { id }, - Borrow(e) => ExprKind::Borrow { - borrow_kind: BorrowKind::Shared, - arg: e.into(), - }, - ConstRef { id } => ExprKind::ConstRef { id }, - Array { fields } => ExprKind::Array { - fields: fields.into_iter().map(|field| field.into()).collect(), - }, - Tuple { fields } => ExprKind::Tuple { - fields: fields.into_iter().map(|field| field.into()).collect(), - }, - kind @ (FnPtr { .. } | TraitConst { .. }) => { - // SH: I see the `Closure` kind, but it's not the same as function pointer? - ExprKind::Todo(format!("FnPtr or TraitConst. kind={:#?}", kind)) + ByteStr(raw, str_style) => LitKind::ByteStr(raw, str_style), + Str(raw, str_style) => LitKind::Str(raw, str_style), + }; + let span = c.span.clone(); + let lit = Spanned { span, node }; + ExprKind::Literal { lit, neg } + } + Adt { info, fields } => ExprKind::Adt(AdtExpr { + info, + fields: fields.into_iter().map(|field| field.into()).collect(), + base: None, + user_ty: None, + }), + // TODO: propagate the generics and trait refs (see #636) + GlobalName { + id, + generics: _, + trait_refs: _, + } => ExprKind::GlobalName { id }, + Borrow(e) => ExprKind::Borrow { + borrow_kind: BorrowKind::Shared, + arg: e.into(), + }, + ConstRef { id } => ExprKind::ConstRef { id }, + Array { fields } => ExprKind::Array { + fields: fields.into_iter().map(|field| field.into()).collect(), + }, + Tuple { fields } => ExprKind::Tuple { + fields: fields.into_iter().map(|field| field.into()).collect(), + }, + kind @ (FnPtr { .. } | TraitConst { .. }) => { + // SH: I see the `Closure` kind, but it's not the same as function pointer? + ExprKind::Todo(format!("FnPtr or TraitConst. kind={:#?}", kind)) + } + Todo(msg) => ExprKind::Todo(msg), + }; + Decorated { + contents: Box::new(kind), + ..c } - Todo(msg) => ExprKind::Todo(msg), - }; - Decorated { - contents: Box::new(kind), - ..c } } -} -pub(crate) fn scalar_int_to_constant_literal<'tcx, S: UnderOwnerState<'tcx>>( - s: &S, - x: rustc_middle::ty::ScalarInt, - ty: rustc_middle::ty::Ty, -) -> ConstantLiteral { - match ty.kind() { - ty::Char => ConstantLiteral::Char( - char::try_from(x) - .s_expect(s, "scalar_int_to_constant_literal: expected a char") - .into(), - ), - ty::Bool => ConstantLiteral::Bool( - x.try_to_bool() - .s_expect(s, "scalar_int_to_constant_literal: expected a bool"), - ), - ty::Int(kind) => { - let v = x.try_to_int(x.size()).s_unwrap(s); - ConstantLiteral::Int(ConstantInt::Int(v, kind.sinto(s))) - } - ty::Uint(kind) => { - let v = x.try_to_uint(x.size()).s_unwrap(s); - ConstantLiteral::Int(ConstantInt::Uint(v, kind.sinto(s))) + pub(crate) fn scalar_int_to_constant_literal<'tcx, S: UnderOwnerState<'tcx>>( + s: &S, + x: rustc_middle::ty::ScalarInt, + ty: rustc_middle::ty::Ty, + ) -> ConstantLiteral { + match ty.kind() { + ty::Char => ConstantLiteral::Char( + char::try_from(x) + .s_expect(s, "scalar_int_to_constant_literal: expected a char") + .into(), + ), + ty::Bool => ConstantLiteral::Bool( + x.try_to_bool() + .s_expect(s, "scalar_int_to_constant_literal: expected a bool"), + ), + ty::Int(kind) => { + let v = x.to_int(x.size()); + ConstantLiteral::Int(ConstantInt::Int(v, kind.sinto(s))) + } + ty::Uint(kind) => { + let v = x.to_uint(x.size()); + ConstantLiteral::Int(ConstantInt::Uint(v, kind.sinto(s))) + } + _ => fatal!( + s, + "scalar_int_to_constant_literal: the type {:?} is not a literal", + ty + ), } - _ => fatal!( - s, - "scalar_int_to_constant_literal: the type {:?} is not a literal", - ty - ), } -} -pub(crate) fn scalar_to_constant_expr<'tcx, S: UnderOwnerState<'tcx>>( - s: &S, - ty: rustc_middle::ty::Ty<'tcx>, - scalar: &rustc_middle::mir::interpret::Scalar, - span: rustc_span::Span, -) -> ConstantExpr { - use rustc_middle::mir::Mutability; - let cspan = span.sinto(s); - // The documentation explicitly says not to match on a scalar. - // We match on the type and use it to convert the value. - let kind = match ty.kind() { - ty::Char | ty::Bool | ty::Int(_) | ty::Uint(_) => { - let scalar_int = scalar.try_to_int().unwrap_or_else(|_| { - fatal!( - s[span], - "Type is primitive, but the scalar {:#?} is not a [Int]", - scalar - ) - }); - ConstantExprKind::Literal(scalar_int_to_constant_literal(s, scalar_int, ty)) - } - ty::Ref(region, ty, Mutability::Not) if region.is_erased() => { - let tcx = s.base().tcx; - let pointer = scalar.to_pointer(&tcx).unwrap_or_else(|_| { - fatal!( - s[span], - "Type is [Ref], but the scalar {:#?} is not a [Pointer]", - scalar - ) - }); - use rustc_middle::mir::interpret::GlobalAlloc; - let contents = match tcx.global_alloc(pointer.provenance.s_unwrap(s)) { + pub(crate) fn scalar_to_constant_expr<'tcx, S: UnderOwnerState<'tcx>>( + s: &S, + ty: rustc_middle::ty::Ty<'tcx>, + scalar: &rustc_middle::mir::interpret::Scalar, + span: rustc_span::Span, + ) -> ConstantExpr { + use rustc_middle::mir::Mutability; + let cspan = span.sinto(s); + // The documentation explicitly says not to match on a scalar. + // We match on the type and use it to convert the value. + let kind = match ty.kind() { + ty::Char | ty::Bool | ty::Int(_) | ty::Uint(_) => { + let scalar_int = scalar.try_to_scalar_int().unwrap_or_else(|_| { + fatal!( + s[span], + "Type is primitive, but the scalar {:#?} is not a [Int]", + scalar + ) + }); + ConstantExprKind::Literal(scalar_int_to_constant_literal(s, scalar_int, ty)) + } + ty::Ref(region, ty, Mutability::Not) if region.is_erased() => { + let tcx = s.base().tcx; + let pointer = scalar.to_pointer(&tcx).unwrap_or_else(|_| { + fatal!( + s[span], + "Type is [Ref], but the scalar {:#?} is not a [Pointer]", + scalar + ) + }); + use rustc_middle::mir::interpret::GlobalAlloc; + let contents = match tcx.global_alloc(pointer.provenance.s_unwrap(s).alloc_id()) { GlobalAlloc::Static(did) => ConstantExprKind::GlobalName { id: did.sinto(s), generics: Vec::new(), trait_refs: Vec::new() }, GlobalAlloc::Memory(alloc) => { let values = alloc.inner().get_bytes_unchecked(rustc_middle::mir::interpret::AllocRange { @@ -261,187 +273,211 @@ pub(crate) fn scalar_to_constant_expr<'tcx, S: UnderOwnerState<'tcx>>( provenance ) }; - ConstantExprKind::Borrow(contents.decorate(ty.sinto(s), cspan.clone())) - } - // A [Scalar] might also be any zero-sized [Adt] or [Tuple] (i.e., unit) - ty::Tuple(ty) if ty.is_empty() => ConstantExprKind::Tuple { fields: vec![] }, - // It seems we can have ADTs when there is only one variant, and this variant doesn't have any fields. - ty::Adt(def, _) - if let [variant_def] = &def.variants().raw - && variant_def.fields.is_empty() => - { - ConstantExprKind::Adt { - info: get_variant_information(def, rustc_abi::FIRST_VARIANT, s), - fields: vec![], + ConstantExprKind::Borrow(contents.decorate(ty.sinto(s), cspan.clone())) } - } - _ => fatal!( - s[span], - "Unexpected type {:#?} for scalar {:#?}", - ty, - scalar - ), - }; - kind.decorate(ty.sinto(s), cspan) -} + // A [Scalar] might also be any zero-sized [Adt] or [Tuple] (i.e., unit) + ty::Tuple(ty) if ty.is_empty() => ConstantExprKind::Tuple { fields: vec![] }, + // It seems we can have ADTs when there is only one variant, and this variant doesn't have any fields. + ty::Adt(def, _) => { + if let [variant_def] = &def.variants().raw { + if variant_def.fields.is_empty() { + ConstantExprKind::Adt { + info: get_variant_information(def, rustc_target::abi::FIRST_VARIANT, s), + fields: vec![], + } + } else { + fatal!( + s[span], + "Unexpected type `ty` for scalar `scalar`. Case `ty::Adt(def, _)`: `variant_def.fields` was not empty"; + {ty, scalar, def, variant_def} + ) + } + } else { + fatal!( + s[span], + "Unexpected type `ty` for scalar `scalar`. Case `ty::Adt(def, _)`: `def.variants().raw` was supposed to contain exactly one variant."; + {ty, scalar, def, &def.variants().raw} + ) + } + } + _ => fatal!( + s[span], + "Unexpected type `ty` for scalar `scalar`"; + {ty, scalar} + ), + }; + kind.decorate(ty.sinto(s), cspan) + } -/// Whether a `DefId` is a `AnonConst`. An anonymous constant is -/// generated by Rustc, hoisting every constat bits from items as -/// separate top-level items. This AnonConst mechanism is internal to -/// Rustc; we don't want to reflect that, instead we prefer inlining -/// those. `is_anon_const` is used to detect such AnonConst so that we -/// can evaluate and inline them. -pub(crate) fn is_anon_const<'tcx>( - did: rustc_span::def_id::DefId, - tcx: rustc_middle::ty::TyCtxt<'tcx>, -) -> bool { - matches!( - tcx.def_path(did).data.last().map(|x| x.data), - Some(rustc_hir::definitions::DefPathData::AnonConst) - ) -} + /// Whether a `DefId` is a `AnonConst`. An anonymous constant is + /// generated by Rustc, hoisting every constat bits from items as + /// separate top-level items. This AnonConst mechanism is internal to + /// Rustc; we don't want to reflect that, instead we prefer inlining + /// those. `is_anon_const` is used to detect such AnonConst so that we + /// can evaluate and inline them. + pub(crate) fn is_anon_const<'tcx>( + did: rustc_span::def_id::DefId, + tcx: rustc_middle::ty::TyCtxt<'tcx>, + ) -> bool { + matches!( + tcx.def_path(did).data.last().map(|x| x.data), + Some(rustc_hir::definitions::DefPathData::AnonConst) + ) + } -fn trait_const_to_constant_expr_kind<'tcx, S: BaseState<'tcx> + HasOwnerId>( - s: &S, - _const_def_id: rustc_hir::def_id::DefId, - generics: rustc_middle::ty::GenericArgsRef<'tcx>, - assoc: &rustc_middle::ty::AssocItem, -) -> ConstantExprKind { - assert!(assoc.trait_item_def_id.is_some()); - let name = assoc.name.to_string(); + fn trait_const_to_constant_expr_kind<'tcx, S: BaseState<'tcx> + HasOwnerId>( + s: &S, + _const_def_id: rustc_hir::def_id::DefId, + generics: rustc_middle::ty::GenericArgsRef<'tcx>, + assoc: &rustc_middle::ty::AssocItem, + ) -> ConstantExprKind { + assert!(assoc.trait_item_def_id.is_some()); + let name = assoc.name.to_string(); - // Retrieve the trait information - let impl_expr = get_trait_info(s, generics, assoc); + // Retrieve the trait information + let impl_expr = get_trait_info(s, generics, assoc); - ConstantExprKind::TraitConst { impl_expr, name } -} + ConstantExprKind::TraitConst { impl_expr, name } + } -impl ConstantExprKind { - pub fn decorate(self, ty: Ty, span: Span) -> Decorated { - Decorated { - contents: Box::new(self), - hir_id: None, - attributes: vec![], - ty, - span, + impl ConstantExprKind { + pub fn decorate(self, ty: Ty, span: Span) -> Decorated { + Decorated { + contents: Box::new(self), + hir_id: None, + attributes: vec![], + ty, + span, + } } } -} -pub enum TranslateUnevalRes { - // TODO: rename - GlobalName(ConstantExprKind), - EvaluatedConstant(T), -} + pub enum TranslateUnevalRes { + // TODO: rename + GlobalName(ConstantExpr), + EvaluatedConstant(T), + } -pub trait ConstantExt<'tcx>: Sized + std::fmt::Debug { - fn eval_constant>(&self, s: &S) -> Option; - - /// Performs a one-step translation of a constant. - /// - When a constant refers to a named top-level constant, we want to use that, thus we translate the constant to a `ConstantExprKind::GlobalName`. This is captured by the variant `TranslateUnevalRes::GlobalName`. - /// - When a constant refers to a anonymous top-level constant, we evaluate it. If the evaluation fails, we report an error: we expect every AnonConst to be reducible. Otherwise, we return the variant `TranslateUnevalRes::EvaluatedConstant`. - fn translate_uneval( - &self, - s: &impl UnderOwnerState<'tcx>, - ucv: rustc_middle::ty::UnevaluatedConst<'tcx>, - ) -> TranslateUnevalRes { - let tcx = s.base().tcx; - if is_anon_const(ucv.def, tcx) { - TranslateUnevalRes::EvaluatedConstant(self.eval_constant(s).unwrap_or_else(|| { - // TODO: This is triggered when compiling using `generic_const_exprs` - supposely_unreachable_fatal!(s, "TranslateUneval"; {self, ucv}); - })) - } else { - let cv = if let Some(assoc) = s.base().tcx.opt_associated_item(ucv.def) { - if assoc.trait_item_def_id.is_some() { - // This must be a trait declaration constant - trait_const_to_constant_expr_kind(s, ucv.def, ucv.args, &assoc) + pub trait ConstantExt<'tcx>: Sized + std::fmt::Debug { + fn eval_constant>(&self, s: &S) -> Option; + + /// Performs a one-step translation of a constant. + /// - When a constant refers to a named top-level constant, we want to use that, thus we translate the constant to a `ConstantExprKind::GlobalName`. This is captured by the variant `TranslateUnevalRes::GlobalName`. + /// - When a constant refers to a anonymous top-level constant, we evaluate it. If the evaluation fails, we report an error: we expect every AnonConst to be reducible. Otherwise, we return the variant `TranslateUnevalRes::EvaluatedConstant`. + fn translate_uneval( + &self, + s: &impl UnderOwnerState<'tcx>, + ucv: rustc_middle::ty::UnevaluatedConst<'tcx>, + span: rustc_span::Span, + ) -> TranslateUnevalRes { + let tcx = s.base().tcx; + if is_anon_const(ucv.def, tcx) { + TranslateUnevalRes::EvaluatedConstant(self.eval_constant(s).unwrap_or_else(|| { + // TODO: This is triggered when compiling using `generic_const_exprs` + supposely_unreachable_fatal!(s, "TranslateUneval"; {self, ucv}); + })) + } else { + let param_env = s.param_env(); + let ty = s.base().tcx.type_of(ucv.def); + let ty = tcx.instantiate_and_normalize_erasing_regions(ucv.args, param_env, ty); + let kind = if let Some(assoc) = s.base().tcx.opt_associated_item(ucv.def) { + if assoc.trait_item_def_id.is_some() { + // This must be a trait declaration constant + trait_const_to_constant_expr_kind(s, ucv.def, ucv.args, &assoc) + } else { + // Constant appearing in an inherent impl block. + + // Solve the trait obligations + let parent_def_id = tcx.parent(ucv.def); + let trait_refs = + solve_item_traits(s, param_env, parent_def_id, ucv.args, None); + + // Convert + let id = ucv.def.sinto(s); + let generics = ucv.args.sinto(s); + ConstantExprKind::GlobalName { + id, + generics, + trait_refs, + } + } } else { - // Constant appearing in an inherent impl block. - - // Solve the trait obligations - let parent_def_id = tcx.parent(ucv.def); - let param_env = s.param_env(); - let trait_refs = solve_item_traits(s, param_env, parent_def_id, ucv.args, None); - - // Convert + // Top-level constant. + assert!(ucv.args.is_empty(), "top-level constant has generics?"); let id = ucv.def.sinto(s); - let generics = ucv.args.sinto(s); ConstantExprKind::GlobalName { id, - generics, - trait_refs, + generics: vec![], + trait_refs: vec![], } - } - } else { - // Top-level constant. - assert!(ucv.args.is_empty(), "top-level constant has generics?"); - let id = ucv.def.sinto(s); - ConstantExprKind::GlobalName { - id, - generics: vec![], - trait_refs: vec![], - } - }; - TranslateUnevalRes::GlobalName(cv) + }; + let cv = kind.decorate(ty.sinto(s), span.sinto(s)); + TranslateUnevalRes::GlobalName(cv) + } } } -} -impl<'tcx> ConstantExt<'tcx> for ty::Const<'tcx> { - fn eval_constant>(&self, s: &S) -> Option { - let evaluated = self.eval(s.base().tcx, s.param_env(), None).ok()?; - let evaluated = ty::Const::new(s.base().tcx, ty::ConstKind::Value(evaluated), self.ty()); - (&evaluated != self).then_some(evaluated) + impl<'tcx> ConstantExt<'tcx> for ty::Const<'tcx> { + fn eval_constant>(&self, s: &S) -> Option { + let (ty, evaluated) = self + .eval(s.base().tcx, s.param_env(), rustc_span::DUMMY_SP) + .ok()?; + let evaluated = ty::Const::new(s.base().tcx, ty::ConstKind::Value(ty, evaluated)); + (&evaluated != self).then_some(evaluated) + } } -} -impl<'tcx> ConstantExt<'tcx> for mir::ConstantKind<'tcx> { - fn eval_constant>(&self, s: &S) -> Option { - let evaluated = self.eval(s.base().tcx, s.param_env(), None).ok()?; - let evaluated = mir::ConstantKind::Val(evaluated, self.ty()); - (&evaluated != self).then_some(evaluated) + impl<'tcx> ConstantExt<'tcx> for mir::Const<'tcx> { + fn eval_constant>(&self, s: &S) -> Option { + let evaluated = self + .eval(s.base().tcx, s.param_env(), rustc_span::DUMMY_SP) + .ok()?; + let evaluated = mir::Const::Val(evaluated, self.ty()); + (&evaluated != self).then_some(evaluated) + } } -} -impl<'tcx, S: UnderOwnerState<'tcx>> SInto for ty::Const<'tcx> { - fn sinto(&self, s: &S) -> ConstantExpr { - use rustc_middle::query::Key; - let span = self.default_span(s.base().tcx); - let kind = match self.kind() { - ty::ConstKind::Param(p) => ConstantExprKind::ConstRef { id: p.sinto(s) }, - ty::ConstKind::Infer(..) => fatal!(s[span], "ty::ConstKind::Infer node? {:#?}", self), - - ty::ConstKind::Unevaluated(ucv) => match self.translate_uneval(s, ucv) { - TranslateUnevalRes::EvaluatedConstant(c) => return c.sinto(s), - TranslateUnevalRes::GlobalName(c) => c, - }, - ty::ConstKind::Value(valtree) => { - return valtree_to_constant_expr(s, valtree, self.ty(), span) - } - ty::ConstKind::Error(_) => fatal!(s[span], "ty::ConstKind::Error"), - ty::ConstKind::Expr(e) => fatal!(s[span], "ty::ConstKind::Expr {:#?}", e), + impl<'tcx, S: UnderOwnerState<'tcx>> SInto for ty::Const<'tcx> { + fn sinto(&self, s: &S) -> ConstantExpr { + use rustc_middle::query::Key; + let span = self.default_span(s.base().tcx); + match self.kind() { + ty::ConstKind::Param(p) => { + let ty = p.find_ty_from_env(s.param_env()); + let kind = ConstantExprKind::ConstRef { id: p.sinto(s) }; + kind.decorate(ty.sinto(s), span.sinto(s)) + } + ty::ConstKind::Infer(..) => { + fatal!(s[span], "ty::ConstKind::Infer node? {:#?}", self) + } + + ty::ConstKind::Unevaluated(ucv) => match self.translate_uneval(s, ucv, span) { + TranslateUnevalRes::EvaluatedConstant(c) => return c.sinto(s), + TranslateUnevalRes::GlobalName(c) => c, + }, + ty::ConstKind::Value(ty, valtree) => valtree_to_constant_expr(s, valtree, ty, span), + ty::ConstKind::Error(_) => fatal!(s[span], "ty::ConstKind::Error"), + ty::ConstKind::Expr(e) => fatal!(s[span], "ty::ConstKind::Expr {:#?}", e), - ty::ConstKind::Bound(i, bound) => { - supposely_unreachable_fatal!(s[span], "ty::ConstKind::Bound"; {i, bound, self.ty()}); + ty::ConstKind::Bound(i, bound) => { + supposely_unreachable_fatal!(s[span], "ty::ConstKind::Bound"; {i, bound}); + } + _ => fatal!(s[span], "unexpected case"), } - _ => fatal!(s[span], "unexpected case"), - }; - kind.decorate(self.ty().sinto(s), span.sinto(s)) + } } -} -// #[tracing::instrument(skip(s))] -pub(crate) fn valtree_to_constant_expr<'tcx, S: UnderOwnerState<'tcx>>( - s: &S, - valtree: rustc_middle::ty::ValTree<'tcx>, - ty: rustc_middle::ty::Ty<'tcx>, - span: rustc_span::Span, -) -> ConstantExpr { - let kind = match (valtree, ty.kind()) { + // #[tracing::instrument(skip(s))] + pub(crate) fn valtree_to_constant_expr<'tcx, S: UnderOwnerState<'tcx>>( + s: &S, + valtree: rustc_middle::ty::ValTree<'tcx>, + ty: rustc_middle::ty::Ty<'tcx>, + span: rustc_span::Span, + ) -> ConstantExpr { + let kind = match (valtree, ty.kind()) { (_, ty::Ref(_, inner_ty, _)) => { ConstantExprKind::Borrow(valtree_to_constant_expr(s, valtree, *inner_ty, span)) } (ty::ValTree::Branch(valtrees), ty::Str) => ConstantExprKind::Literal( ConstantLiteral::byte_str(valtrees.iter().map(|x| match x { - ty::ValTree::Leaf(leaf) => leaf.try_to_u8().unwrap_or_else(|e| fatal!(s[span], "Expected a u8 leaf while translating a str literal, got something else. Error: {:#?}", e)), + ty::ValTree::Leaf(leaf) => leaf.to_u8(), _ => fatal!(s[span], "Expected a flat list of leaves while translating a str literal, got a arbitrary valtree.") }).collect(), StrStyle::Cooked)) , @@ -489,100 +525,105 @@ pub(crate) fn valtree_to_constant_expr<'tcx, S: UnderOwnerState<'tcx>>( {valtree, ty} ), }; - kind.decorate(ty.sinto(s), span.sinto(s)) -} + kind.decorate(ty.sinto(s), span.sinto(s)) + } -pub(crate) fn const_value_reference_to_constant_expr<'tcx, S: UnderOwnerState<'tcx>>( - s: &S, - ty: rustc_middle::ty::Ty<'tcx>, - val: rustc_middle::mir::interpret::ConstValue<'tcx>, - span: rustc_span::Span, -) -> ConstantExpr { - let tcx = s.base().tcx; - - let dc = tcx - .try_destructure_mir_constant_for_diagnostics((val, ty)) - .s_unwrap(s); - - // Iterate over the fields, which should be values - assert!(dc.variant.is_none()); - - // The type should be tuple - let hax_ty = ty.sinto(s); - match &hax_ty { - Ty::Tuple(_) => (), - _ => { - fatal!(s[span], "Expected the type to be tuple: {:?}", val) - } - }; + pub(crate) fn const_value_reference_to_constant_expr<'tcx, S: UnderOwnerState<'tcx>>( + s: &S, + ty: rustc_middle::ty::Ty<'tcx>, + val: rustc_middle::mir::ConstValue<'tcx>, + span: rustc_span::Span, + ) -> ConstantExpr { + let tcx = s.base().tcx; - // Below: we are mutually recursive with [const_value_to_constant_expr], - // which takes a [ConstantKind] as input, but it should be - // ok because we call it on a strictly smaller value. - let fields: Vec = dc - .fields - .iter() - .copied() - .map(|(val, ty)| const_value_to_constant_expr(s, ty, val, span)) - .collect(); - (ConstantExprKind::Tuple { fields }).decorate(hax_ty, span.sinto(s)) -} + let dc = tcx + .try_destructure_mir_constant_for_user_output(val, ty) + .s_unwrap(s); -pub fn const_value_to_constant_expr<'tcx, S: UnderOwnerState<'tcx>>( - s: &S, - ty: rustc_middle::ty::Ty<'tcx>, - val: rustc_middle::mir::interpret::ConstValue<'tcx>, - span: rustc_span::Span, -) -> ConstantExpr { - use rustc_middle::mir::interpret::ConstValue; - match val { - ConstValue::Scalar(scalar) => scalar_to_constant_expr(s, ty, &scalar, span), - ConstValue::Indirect { .. } => const_value_reference_to_constant_expr(s, ty, val, span), - ConstValue::Slice { data, start, end } => { - let start = start.try_into().unwrap(); - let end = end.try_into().unwrap(); - // This is outside of the interpreter, so we are okay to use - // `inspect_with_uninit_and_ptr_outside_interpreter`. Moreover this is a string/byte - // literal, so we don't have to care about initialization. - // This is copied from `ConstantValue::try_get_slice_bytes_for_diagnostics`, available - // only in a more recent rustc version. - let slice: &[u8] = data - .inner() - .inspect_with_uninit_and_ptr_outside_interpreter(start..end); - ConstantExprKind::Literal(ConstantLiteral::byte_str(slice.to_vec(), StrStyle::Cooked)) + // Iterate over the fields, which should be values + assert!(dc.variant.is_none()); + + // The type should be tuple + let hax_ty = ty.sinto(s); + match &hax_ty { + Ty::Tuple(_) => (), + _ => { + fatal!(s[span], "Expected the type to be tuple: {:?}", val) + } + }; + + // Below: we are mutually recursive with [const_value_to_constant_expr], + // which takes a [Const] as input, but it should be + // ok because we call it on a strictly smaller value. + let fields: Vec = dc + .fields + .iter() + .copied() + .map(|(val, ty)| const_value_to_constant_expr(s, ty, val, span)) + .collect(); + (ConstantExprKind::Tuple { fields }).decorate(hax_ty, span.sinto(s)) + } + + pub fn const_value_to_constant_expr<'tcx, S: UnderOwnerState<'tcx>>( + s: &S, + ty: rustc_middle::ty::Ty<'tcx>, + val: rustc_middle::mir::ConstValue<'tcx>, + span: rustc_span::Span, + ) -> ConstantExpr { + use rustc_middle::mir::ConstValue; + match val { + ConstValue::Scalar(scalar) => scalar_to_constant_expr(s, ty, &scalar, span), + ConstValue::Indirect { .. } => const_value_reference_to_constant_expr(s, ty, val, span), + ConstValue::Slice { data, meta } => { + let end = meta.try_into().unwrap(); + // This is outside of the interpreter, so we are okay to use + // `inspect_with_uninit_and_ptr_outside_interpreter`. Moreover this is a string/byte + // literal, so we don't have to care about initialization. + // This is copied from `ConstantValue::try_get_slice_bytes_for_diagnostics`, available + // only in a more recent rustc version. + let slice: &[u8] = data + .inner() + .inspect_with_uninit_and_ptr_outside_interpreter(0..end); + ConstantExprKind::Literal(ConstantLiteral::byte_str( + slice.to_vec(), + StrStyle::Cooked, + )) .decorate(ty.sinto(s), span.sinto(s)) - } - ConstValue::ZeroSized { .. } => { - // Should be unit - let hty = ty.sinto(s); - let cv = match &hty { - Ty::Tuple(tys) if tys.is_empty() => ConstantExprKind::Tuple { fields: Vec::new() }, - Ty::Arrow(_) => match ty.kind() { - rustc_middle::ty::TyKind::FnDef(def_id, args) => { - let (def_id, generics, generics_impls, method_impl) = - get_function_from_def_id_and_generics(s, *def_id, args); - - ConstantExprKind::FnPtr { - def_id, - generics, - generics_impls, - method_impl, - } + } + ConstValue::ZeroSized { .. } => { + // Should be unit + let hty = ty.sinto(s); + let cv = match &hty { + Ty::Tuple(tys) if tys.is_empty() => { + ConstantExprKind::Tuple { fields: Vec::new() } } - kind => { - fatal!(s[span], "Unexpected:"; {kind}) + Ty::Arrow(_) => match ty.kind() { + rustc_middle::ty::TyKind::FnDef(def_id, args) => { + let (def_id, generics, generics_impls, method_impl) = + get_function_from_def_id_and_generics(s, *def_id, args); + + ConstantExprKind::FnPtr { + def_id, + generics, + generics_impls, + method_impl, + } + } + kind => { + fatal!(s[span], "Unexpected:"; {kind}) + } + }, + _ => { + fatal!( + s[span], + "Expected the type to be tuple or arrow"; + {val, ty} + ) } - }, - _ => { - fatal!( - s[span], - "Expected the type to be tuple or arrow"; - {val, ty} - ) - } - }; + }; - cv.decorate(hty, span.sinto(s)) + cv.decorate(hty, span.sinto(s)) + } } } } diff --git a/frontend/exporter/src/index_vec.rs b/frontend/exporter/src/index_vec.rs index 6fdeecb88..950af531c 100644 --- a/frontend/exporter/src/index_vec.rs +++ b/frontend/exporter/src/index_vec.rs @@ -1,22 +1,25 @@ use crate::prelude::*; -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] -pub struct IndexVec { +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct IndexVec { pub raw: Vec, _marker: std::marker::PhantomData, } -impl Into> for rustc_index::IndexVec { - fn into(self) -> IndexVec { - IndexVec { - raw: self.raw, - _marker: std::marker::PhantomData, - } +#[cfg(feature = "rustc")] +impl IndexVec { + pub fn into_iter_enumerated( + self, + ) -> impl DoubleEndedIterator + ExactSizeIterator { + rustc_index::IndexVec::from_raw(self.raw).into_iter_enumerated() + } + pub fn into_iter(self) -> impl DoubleEndedIterator + ExactSizeIterator { + self.raw.into_iter() } } +#[cfg(feature = "rustc")] impl std::ops::Deref for IndexVec { type Target = rustc_index::IndexSlice; fn deref(&self) -> &Self::Target { @@ -24,19 +27,26 @@ impl std::ops::Deref for IndexVec { } } +#[cfg(feature = "rustc")] impl std::ops::DerefMut for IndexVec { fn deref_mut(&mut self) -> &mut Self::Target { Self::Target::from_raw_mut(&mut self.raw) } } -impl< - S, - J: rustc_index::Idx, - I: rustc_index::Idx + SInto, - U: Clone, /*TODO: remove me?*/ - T: SInto, - > SInto> for rustc_index::IndexSlice +#[cfg(feature = "rustc")] +impl Into> for rustc_index::IndexVec { + fn into(self) -> IndexVec { + IndexVec { + raw: self.raw, + _marker: std::marker::PhantomData, + } + } +} + +#[cfg(feature = "rustc")] +impl, U: Clone, T: SInto> + SInto> for rustc_index::IndexSlice { fn sinto(&self, s: &S) -> IndexVec { IndexVec { @@ -46,13 +56,28 @@ impl< } } +#[cfg(feature = "rustc")] +impl FromIterator for IndexVec +where + I: rustc_index::Idx, +{ + #[inline] + fn from_iter>(iter: It) -> Self { + Self { + raw: Vec::from_iter(iter), + _marker: std::marker::PhantomData, + } + } +} + macro_rules! make_idx_wrapper { ($($mod:ident)::+, $type:ident) => { - #[derive(Copy, Clone, Eq, Debug, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize, JsonSchema)] + #[derive_group(Serializers)]#[derive(Copy, Clone, Eq, Debug, Hash, PartialEq, PartialOrd, Ord, JsonSchema)] #[serde(untagged)] pub enum $type { $type(usize), } + #[cfg(feature = "rustc")] const _: () = { use rustc_index::Idx; type OriginalType = $($mod::)+$type; diff --git a/frontend/exporter/src/lib.rs b/frontend/exporter/src/lib.rs index f15880286..aefe44096 100644 --- a/frontend/exporter/src/lib.rs +++ b/frontend/exporter/src/lib.rs @@ -1,42 +1,54 @@ -#![feature(rustc_private)] -#![feature(box_patterns)] -#![feature(concat_idents)] -#![feature(trait_alias)] -#![feature(type_changing_struct_update)] -#![feature(macro_metavar_expr)] -#![feature(if_let_guard)] -#![feature(let_chains)] -#![allow(incomplete_features)] -#![feature(specialization)] -#![feature(return_position_impl_trait_in_trait)] #![allow(rustdoc::private_intra_doc_links)] +#![cfg_attr(feature = "rustc", feature(type_changing_struct_update))] +#![cfg_attr(feature = "rustc", feature(macro_metavar_expr))] +#![cfg_attr(feature = "rustc", feature(concat_idents))] +#![cfg_attr(feature = "rustc", feature(trait_alias))] +#![cfg_attr(feature = "rustc", feature(rustc_private))] -extern crate rustc_abi; -extern crate rustc_ast; -extern crate rustc_ast_pretty; -extern crate rustc_data_structures; -extern crate rustc_driver; -extern crate rustc_errors; -extern crate rustc_hir; -extern crate rustc_hir_analysis; -extern crate rustc_index; -extern crate rustc_infer; -extern crate rustc_interface; -extern crate rustc_middle; -extern crate rustc_mir_build; -extern crate rustc_session; -extern crate rustc_span; -extern crate rustc_target; -extern crate rustc_trait_selection; -extern crate rustc_type_ir; +macro_rules! cfg_feature_rustc { + ($($item:item)*) => { + $( + #[cfg(feature = "rustc")] + $item + )* + } +} + +cfg_feature_rustc! { + // When the feature `rustc` is enabled, we enable the bridges + // between rustc ASTs, which are defined in the crates + // `rustc_*`. We thus need to import them with `extern crate + // rustc_*` + extern crate rustc_abi; + extern crate rustc_ast; + extern crate rustc_ast_pretty; + extern crate rustc_attr; + extern crate rustc_data_structures; + extern crate rustc_driver; + extern crate rustc_errors; + extern crate rustc_hir; + extern crate rustc_hir_analysis; + extern crate rustc_index; + extern crate rustc_infer; + extern crate rustc_interface; + extern crate rustc_middle; + extern crate rustc_mir_build; + extern crate rustc_session; + extern crate rustc_span; + extern crate rustc_target; + extern crate rustc_trait_selection; + extern crate rustc_type_ir; + + mod rustc_utils; + pub mod state; + mod utils; + mod deterministic_hash; +} mod body; mod constant_utils; -mod rustc_utils; -pub mod state; mod types; -mod deterministic_hash; mod index_vec; mod prelude; @@ -45,7 +57,6 @@ pub use prelude::*; mod sinto; mod traits; -mod utils; pub use hax_adt_into::AdtInto; pub use sinto::SInto; diff --git a/frontend/exporter/src/prelude.rs b/frontend/exporter/src/prelude.rs index 977d3d4c5..c7fd69104 100644 --- a/frontend/exporter/src/prelude.rs +++ b/frontend/exporter/src/prelude.rs @@ -1,4 +1,3 @@ -pub(crate) use crate::utils::*; pub use crate::*; pub use schemars::{schema_for, JsonSchema}; pub use serde::{Deserialize, Serialize}; @@ -9,7 +8,16 @@ pub use std::rc::Rc; pub use crate::body::*; pub use crate::constant_utils::*; pub use crate::index_vec::*; -pub use crate::rustc_utils::*; -pub use crate::state::*; pub use crate::traits::*; pub use crate::types::*; + +#[cfg(feature = "rustc")] +pub use self::rustc::*; +#[cfg(feature = "rustc")] +pub mod rustc { + pub use crate::rustc_utils::*; + pub use crate::state::*; + pub use crate::utils::*; +} + +pub(crate) use hax_adt_into::derive_group; diff --git a/frontend/exporter/src/rustc_utils.rs b/frontend/exporter/src/rustc_utils.rs index f83248752..ee3979be3 100644 --- a/frontend/exporter/src/rustc_utils.rs +++ b/frontend/exporter/src/rustc_utils.rs @@ -23,7 +23,7 @@ impl<'tcx> ty::Binder<'tcx, ty::PredicateKind<'tcx>> { } } -#[derive(Clone, Debug, Eq, PartialEq, Hash)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] pub struct AnnotatedPredicate<'tcx> { pub is_extra_self_predicate: bool, /// Note: they are all actually `Clause`s. @@ -110,7 +110,7 @@ pub(crate) fn arrow_of_sig<'tcx, S: UnderOwnerState<'tcx>>(sig: &ty::PolyFnSig<' #[tracing::instrument(skip(s))] pub(crate) fn get_variant_information<'s, S: UnderOwnerState<'s>>( adt_def: &ty::AdtDef<'s>, - variant_index: rustc_abi::VariantIdx, + variant_index: rustc_target::abi::VariantIdx, s: &S, ) -> VariantInformations { s_assert!(s, !adt_def.is_union() || *CORE_EXTRACTION_MODE); @@ -198,7 +198,7 @@ pub(crate) fn read_span_from_file(span: &Span) -> Result { #[tracing::instrument(skip(sess))] pub fn translate_span(span: rustc_span::Span, sess: &rustc_session::Session) -> Span { - let smap: &rustc_span::source_map::SourceMap = sess.parse_sess.source_map(); + let smap: &rustc_span::source_map::SourceMap = sess.psess.source_map(); let filename = smap.span_to_filename(span); let lo = smap.lookup_char_pos(span.lo()); diff --git a/frontend/exporter/src/sinto.rs b/frontend/exporter/src/sinto.rs index 6fedd7267..dc162aa70 100644 --- a/frontend/exporter/src/sinto.rs +++ b/frontend/exporter/src/sinto.rs @@ -1,5 +1,4 @@ -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; +use crate::prelude::{derive_group, JsonSchema}; pub trait SInto { fn sinto(&self, s: &S) -> To; @@ -8,12 +7,14 @@ pub trait SInto { #[macro_export] macro_rules! sinto_todo { ($($mod:ident)::+, $type:ident$(<$($lts:lifetime),*$(,)?>)? as $renamed:ident) => { - #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] + #[derive_group(Serializers)] + #[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum $renamed { $type { todo: String }, } + #[cfg(feature = "rustc")] impl<$($($lts,)*)? S> SInto for $($mod)::+::$type$(<$($lts,)*>)? { fn sinto(&self, _: &S) -> $renamed { $renamed::$type{todo: format!("{:?}", self)} @@ -29,6 +30,7 @@ macro_rules! sinto_todo { macro_rules! sinto_as_usize { ($($mod:ident)::+, $type:ident$(<$($lts:lifetime),*$(,)?>)?) => { pub type $type = usize; + #[cfg(feature = "rustc")] impl<$($($lts,)*)? S> SInto for $($mod)::+::$type$(<$($lts,)*>)? { fn sinto(&self, _: &S) -> $type { self.as_usize() @@ -64,8 +66,12 @@ impl> SInto> for Option { } impl> SInto for Box { fn sinto(&self, s: &S) -> D { - let box x = self; - x.sinto(s) + (**self).sinto(s) + } +} +impl> SInto for &T { + fn sinto(&self, s: &S) -> D { + (**self).sinto(s) } } impl> SInto> for [T] { @@ -75,8 +81,7 @@ impl> SInto> for [T] { } impl> SInto> for Box<[T]> { fn sinto(&self, s: &S) -> Vec { - let box x = self; - x.into_iter().map(|x| x.sinto(s)).collect() + (&*self).into_iter().map(|x| x.sinto(s)).collect() } } @@ -85,6 +90,7 @@ impl> SInto> for Vec { self.into_iter().map(|x| x.sinto(s)).collect() } } +#[cfg(feature = "rustc")] impl SInto> for rustc_data_structures::sync::Lrc<[u8]> { fn sinto(&self, _s: &S) -> Vec { (**self).iter().cloned().collect() diff --git a/frontend/exporter/src/state.rs b/frontend/exporter/src/state.rs index 2b70d4df9..0c036a6f5 100644 --- a/frontend/exporter/src/state.rs +++ b/frontend/exporter/src/state.rs @@ -99,7 +99,7 @@ macro_rules! mk { mod types { use crate::prelude::*; use std::cell::RefCell; - use std::collections::{HashMap, HashSet}; + use std::collections::HashSet; pub struct LocalContextS { pub vars: HashMap, @@ -131,6 +131,12 @@ mod types { >, >, pub tcx: rustc_middle::ty::TyCtxt<'tcx>, + /// Rust doesn't enforce bounds on generic parameters in type + /// aliases. Thus, when translating type aliases, we need to + /// disable the resolution of implementation expressions. For + /// more details, please see + /// https://github.com/hacspec/hax/issues/707. + pub ty_alias_mode: bool, } impl<'tcx> Base<'tcx> { @@ -149,6 +155,7 @@ mod types { local_ctx: Rc::new(RefCell::new(LocalContextS::new())), exported_spans: Rc::new(RefCell::new(HashSet::new())), exported_def_ids: Rc::new(RefCell::new(HashSet::new())), + ty_alias_mode: false, } } } @@ -169,7 +176,7 @@ mk!( } ); -pub use types::*; +pub use self::types::*; impl<'tcx> State, (), (), ()> { pub fn new( @@ -228,18 +235,13 @@ pub fn with_owner_id<'tcx, THIR, MIR>( } pub trait BaseState<'tcx> = HasBase<'tcx> + Clone + IsState<'tcx>; + /// State of anything below a `owner_id` pub trait UnderOwnerState<'tcx> = BaseState<'tcx> + HasOwnerId; -/// Meta-informations about an `impl TRAIT for -/// TYPE where PREDICATES {}` -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] -pub struct ImplInfos { - pub generics: TyGenerics, - pub clauses: Vec<(Clause, Span)>, - pub typ: Ty, - pub trait_ref: Option, -} +/// While translating expressions, we expect to always have a THIR +/// body and an `owner_id` in the state +pub trait ExprState<'tcx> = UnderOwnerState<'tcx> + HasThir<'tcx>; impl ImplInfos { fn from<'tcx>(base: Base<'tcx>, did: rustc_hir::def_id::DefId) -> Self { diff --git a/frontend/exporter/src/traits.rs b/frontend/exporter/src/traits.rs index 648e45092..74feb4296 100644 --- a/frontend/exporter/src/traits.rs +++ b/frontend/exporter/src/traits.rs @@ -2,18 +2,19 @@ use crate::prelude::*; #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx> >, from: search_clause::PathChunk<'tcx>, state: S as tcx)] -#[derive( - Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, JsonSchema, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, JsonSchema)] pub enum ImplExprPathChunk { AssocItem { item: AssocItem, predicate: Binder, + #[value(predicate.predicate_id(tcx))] predicate_id: PredicateId, index: usize, }, Parent { predicate: Binder, + #[value(predicate.predicate_id(tcx))] predicate_id: PredicateId, index: usize, }, @@ -21,9 +22,8 @@ pub enum ImplExprPathChunk { /// The source of a particular trait implementation. Most often this is either `Concrete` for a /// concrete `impl Trait for Type {}` item, or `LocalBound` for a context-bound `where T: Trait`. -#[derive( - Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, JsonSchema, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, JsonSchema)] pub enum ImplExprAtom { /// A concrete `impl Trait for Type {}` item. Concrete { @@ -58,9 +58,8 @@ pub enum ImplExprAtom { /// need to combine several concrete trait implementation items. For example, `((1u8, 2u8), /// "hello").clone()` combines the generic implementation of `Clone` for `(A, B)` with the /// concrete implementations for `u8` and `&str`, represented as a tree. -#[derive( - Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, JsonSchema, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, JsonSchema)] pub struct ImplExpr { /// The trait this is an impl for. pub r#trait: TraitRef, @@ -70,449 +69,471 @@ pub struct ImplExpr { pub args: Vec, } -// FIXME: this has visibility `pub(crate)` only because of https://github.com/rust-lang/rust/issues/83049 -pub(crate) mod search_clause { - use crate::prelude::UnderOwnerState; - use crate::rustc_utils::*; - use crate::{IntoPredicateId, PredicateId}; - use rustc_middle::ty::*; - - fn predicates_to_poly_trait_predicates<'tcx>( - tcx: TyCtxt<'tcx>, - predicates: impl Iterator>, - generics: GenericArgsRef<'tcx>, - ) -> impl Iterator> { - predicates - .map(move |pred| pred.kind().subst(tcx, generics)) - .filter_map(|pred| pred.as_poly_trait_predicate()) - } +#[cfg(feature = "rustc")] +pub mod rustc { + use super::*; + // FIXME: this has visibility `pub(crate)` only because of https://github.com/rust-lang/rust/issues/83049 + pub(crate) mod search_clause { + use crate::prelude::UnderOwnerState; + use crate::rustc_utils::*; + use rustc_middle::ty::*; - #[derive(Clone, Debug)] - pub enum PathChunk<'tcx> { - AssocItem { - item: AssocItem, - predicate: PolyTraitPredicate<'tcx>, - predicate_id: PredicateId, - index: usize, - }, - Parent { - predicate: PolyTraitPredicate<'tcx>, - predicate_id: PredicateId, - index: usize, - }, - } - pub type Path<'tcx> = Vec>; - - /// Custom equality on `Predicate`s. - /// - /// Sometimes Rustc inserts extra generic arguments: I noticed - /// some `__H` second argument given to core::hash::Hash for - /// instance. `__H` seems to be inserted in [1]. Such extra - /// arguments seems to be ignored by `default_print_def_path` [2]. - /// - /// Hence, for now, equality is decided by comparing the debug - /// string representations of `Predicate`s. - /// - /// Note there exist also predicates that are different, - /// `Eq`-wise, but whose `sinto` counterpart are equal. - /// - /// TODO: figure out how to implement this function in a sane way. - /// - /// [1]: https://github.com/rust-lang/rust/blob/b0889cb4ed0e6f3ed9f440180678872b02e7052c/compiler/rustc_builtin_macros/src/deriving/hash.rs#L20 - /// [2]: https://github.com/rust-lang/rust/blob/b0889cb4ed0e6f3ed9f440180678872b02e7052c/compiler/rustc_middle/src/ty/print/mod.rs#L141 - fn predicate_equality<'tcx, S: UnderOwnerState<'tcx>>( - x: Predicate<'tcx>, - y: Predicate<'tcx>, - param_env: rustc_middle::ty::ParamEnv<'tcx>, - s: &S, - ) -> bool { - let tcx = s.base().tcx; - let erase_and_norm = - |x| tcx.erase_regions(tcx.try_normalize_erasing_regions(param_env, x).unwrap_or(x)); - // Lifetime and constantness are irrelevant when resolving instances - let x = erase_and_norm(x); - let y = erase_and_norm(y); - let sx = format!("{:?}", x.kind().skip_binder()); - let sy = format!("{:?}", y.kind().skip_binder()); - let result = sx == sy; - const DEBUG: bool = false; - if DEBUG && result { - use crate::{Predicate, SInto}; - let xs: Predicate = x.sinto(s); - let ys: Predicate = y.sinto(s); - if x != y { - eprintln!("######################## predicate_equality ########################"); - eprintln!("x={:#?}", x); - eprintln!("y={:#?}", y); - eprintln!("######################## sinto ########################"); - eprintln!("sinto(x)={:#?}", xs); - eprintln!("sinto(y)={:#?}", ys); - } + fn predicates_to_poly_trait_predicates<'tcx>( + tcx: TyCtxt<'tcx>, + predicates: impl Iterator>, + generics: GenericArgsRef<'tcx>, + ) -> impl Iterator> { + predicates + .map(move |pred| pred.kind().subst(tcx, generics)) + .filter_map(|pred| pred.as_poly_trait_predicate()) } - result - } - #[extension_traits::extension(pub trait TraitPredicateExt)] - impl<'tcx, S: UnderOwnerState<'tcx>> PolyTraitPredicate<'tcx> { - #[tracing::instrument(level = "trace", skip(s))] - fn parents_trait_predicates(self, s: &S) -> Vec<(usize, PolyTraitPredicate<'tcx>)> { - let tcx = s.base().tcx; - let predicates = tcx - .predicates_defined_on_or_above(self.def_id()) - .into_iter() - .map(|apred| apred.predicate); - predicates_to_poly_trait_predicates(tcx, predicates, self.skip_binder().trait_ref.args) - .enumerate() - .collect() + #[derive(Clone, Debug)] + pub enum PathChunk<'tcx> { + AssocItem { + item: AssocItem, + predicate: PolyTraitPredicate<'tcx>, + index: usize, + }, + Parent { + predicate: PolyTraitPredicate<'tcx>, + index: usize, + }, } - #[tracing::instrument(level = "trace", skip(s))] - fn associated_items_trait_predicates( - self, + pub type Path<'tcx> = Vec>; + + /// Custom equality on `Predicate`s. + /// + /// Sometimes Rustc inserts extra generic arguments: I noticed + /// some `__H` second argument given to core::hash::Hash for + /// instance. `__H` seems to be inserted in [1]. Such extra + /// arguments seems to be ignored by `default_print_def_path` [2]. + /// + /// Hence, for now, equality is decided by comparing the debug + /// string representations of `Predicate`s. + /// + /// Note there exist also predicates that are different, + /// `Eq`-wise, but whose `sinto` counterpart are equal. + /// + /// TODO: figure out how to implement this function in a sane way. + /// + /// [1]: https://github.com/rust-lang/rust/blob/b0889cb4ed0e6f3ed9f440180678872b02e7052c/compiler/rustc_builtin_macros/src/deriving/hash.rs#L20 + /// [2]: https://github.com/rust-lang/rust/blob/b0889cb4ed0e6f3ed9f440180678872b02e7052c/compiler/rustc_middle/src/ty/print/mod.rs#L141 + fn predicate_equality<'tcx, S: UnderOwnerState<'tcx>>( + x: Predicate<'tcx>, + y: Predicate<'tcx>, + param_env: rustc_middle::ty::ParamEnv<'tcx>, s: &S, - ) -> Vec<( - AssocItem, - EarlyBinder)>>, - )> { + ) -> bool { let tcx = s.base().tcx; - tcx.associated_items(self.def_id()) - .in_definition_order() - .filter(|item| item.kind == AssocKind::Type) - .copied() - .map(|item| { - let bounds = tcx.item_bounds(item.def_id).map_bound(|clauses| { - predicates_to_poly_trait_predicates( - tcx, - clauses.into_iter().map(|clause| clause.as_predicate()), - self.skip_binder().trait_ref.args, - ) - .enumerate() - .collect() - }); - (item, bounds) - }) + let erase_and_norm = + |x| tcx.erase_regions(tcx.try_normalize_erasing_regions(param_env, x).unwrap_or(x)); + // Lifetime and constantness are irrelevant when resolving instances + let x = erase_and_norm(x); + let y = erase_and_norm(y); + let sx = format!("{:?}", x.kind().skip_binder()); + let sy = format!("{:?}", y.kind().skip_binder()); + let result = sx == sy; + const DEBUG: bool = false; + if DEBUG && result { + use crate::{Predicate, SInto}; + let xs: Predicate = x.sinto(s); + let ys: Predicate = y.sinto(s); + if x != y { + eprintln!( + "######################## predicate_equality ########################" + ); + eprintln!("x={:#?}", x); + eprintln!("y={:#?}", y); + eprintln!( + "######################## sinto ########################" + ); + eprintln!("sinto(x)={:#?}", xs); + eprintln!("sinto(y)={:#?}", ys); + } + } + result + } + + #[extension_traits::extension(pub trait TraitPredicateExt)] + impl<'tcx, S: UnderOwnerState<'tcx>> PolyTraitPredicate<'tcx> { + #[tracing::instrument(level = "trace", skip(s))] + fn parents_trait_predicates(self, s: &S) -> Vec<(usize, PolyTraitPredicate<'tcx>)> { + let tcx = s.base().tcx; + let predicates = tcx + .predicates_defined_on_or_above(self.def_id()) + .into_iter() + .map(|apred| apred.predicate); + predicates_to_poly_trait_predicates( + tcx, + predicates, + self.skip_binder().trait_ref.args, + ) + .enumerate() .collect() + } + #[tracing::instrument(level = "trace", skip(s))] + fn associated_items_trait_predicates( + self, + s: &S, + ) -> Vec<( + AssocItem, + EarlyBinder<'tcx, Vec<(usize, PolyTraitPredicate<'tcx>)>>, + )> { + let tcx = s.base().tcx; + tcx.associated_items(self.def_id()) + .in_definition_order() + .filter(|item| item.kind == AssocKind::Type) + .copied() + .map(|item| { + let bounds = tcx.item_bounds(item.def_id).map_bound(|clauses| { + predicates_to_poly_trait_predicates( + tcx, + clauses.into_iter().map(|clause| clause.as_predicate()), + self.skip_binder().trait_ref.args, + ) + .enumerate() + .collect() + }); + (item, bounds) + }) + .collect() + } } - #[tracing::instrument(level = "trace", skip(s))] - fn path_to( - self, + #[tracing::instrument(level = "trace", skip(s, param_env))] + pub fn path_to<'tcx, S: UnderOwnerState<'tcx>>( + starting_points: &[AnnotatedPredicate<'tcx>], s: &S, target: PolyTraitRef<'tcx>, param_env: rustc_middle::ty::ParamEnv<'tcx>, - ) -> Option> { + ) -> Option<(Path<'tcx>, AnnotatedPredicate<'tcx>)> { let tcx = s.base().tcx; - if predicate_equality( - self.to_predicate(tcx), - target.to_predicate(tcx), - param_env, - s, - ) { - return Some(vec![]); - } - let recurse = |p: Self| { - if p == self { - return None; - } - p.path_to(s, target, param_env) - }; - fn cons(hd: T, tail: Vec) -> Vec { - vec![hd].into_iter().chain(tail.into_iter()).collect() + /// A candidate projects `self` along a path reaching some + /// predicate. A candidate is selected when its predicate + /// is the one expected, aka `target`. + #[derive(Debug)] + struct Candidate<'tcx> { + path: Path<'tcx>, + pred: PolyTraitPredicate<'tcx>, + origin: AnnotatedPredicate<'tcx>, } - self.parents_trait_predicates(s) + + use std::collections::VecDeque; + let mut candidates: VecDeque> = starting_points .into_iter() - .filter_map(|(index, p)| { - recurse(p).map(|path| { - cons( - PathChunk::Parent { - predicate: p, - predicate_id: p.predicate_id(s), - index, - }, - path, - ) + .filter_map(|pred| { + let clause = pred.predicate.as_trait_clause(); + clause.map(|clause| Candidate { + path: vec![], + pred: clause, + origin: *pred, }) }) - .max_by_key(|path| path.len()) - .or_else(|| { - self.associated_items_trait_predicates(s) - .into_iter() - .filter_map(|(item, binder)| { - binder.skip_binder().into_iter().find_map(|(index, p)| { - recurse(p).map(|path| { - cons( - PathChunk::AssocItem { - item, - predicate_id: p.predicate_id(s), - predicate: p, - index, - }, - path, - ) - }) - }) - }) - .max_by_key(|path| path.len()) - }) + .collect(); + + let target_pred = target.upcast(tcx); + let mut seen = std::collections::HashSet::new(); + + while let Some(candidate) = candidates.pop_front() { + { + // If a predicate was already seen, we know it is + // not the one we are looking for: we skip it. + if seen.contains(&candidate.pred) { + continue; + } + seen.insert(candidate.pred); + } + + // if the candidate equals the target, let's return its path + if predicate_equality(candidate.pred.upcast(tcx), target_pred, param_env, s) { + return Some((candidate.path, candidate.origin)); + } + + // otherwise, we add to the queue all paths reachable from the candidate + for (index, parent_pred) in candidate.pred.parents_trait_predicates(s) { + let mut path = candidate.path.clone(); + path.push(PathChunk::Parent { + predicate: parent_pred, + index, + }); + candidates.push_back(Candidate { + pred: parent_pred, + path, + origin: candidate.origin, + }); + } + for (item, binder) in candidate.pred.associated_items_trait_predicates(s) { + for (index, parent_pred) in binder.skip_binder().into_iter() { + let mut path = candidate.path.clone(); + path.push(PathChunk::AssocItem { + item, + predicate: parent_pred, + index, + }); + candidates.push_back(Candidate { + pred: parent_pred, + path, + origin: candidate.origin, + }); + } + } + } + None } } -} -impl ImplExprAtom { - fn with_args(self, args: Vec, r#trait: TraitRef) -> ImplExpr { - ImplExpr { - r#impl: self, - args, - r#trait, + impl ImplExprAtom { + fn with_args(self, args: Vec, r#trait: TraitRef) -> ImplExpr { + ImplExpr { + r#impl: self, + args, + r#trait, + } } } -} -#[tracing::instrument(level = "trace", skip(s))] -fn impl_exprs<'tcx, S: UnderOwnerState<'tcx>>( - s: &S, - obligations: &Vec< - rustc_trait_selection::traits::Obligation<'tcx, rustc_middle::ty::Predicate<'tcx>>, - >, -) -> Vec { - obligations - .into_iter() - .flat_map(|obligation| { - obligation - .predicate - .kind() - .as_poly_trait_predicate() - .map(|trait_ref| { - trait_ref - .map_bound(|p| p.trait_ref) - .impl_expr(s, obligation.param_env) - }) - }) - .collect() -} - -pub trait IntoImplExpr<'tcx> { - fn impl_expr>( - &self, + #[tracing::instrument(level = "trace", skip(s))] + fn impl_exprs<'tcx, S: UnderOwnerState<'tcx>>( s: &S, - param_env: rustc_middle::ty::ParamEnv<'tcx>, - ) -> ImplExpr; -} + obligations: &Vec< + rustc_trait_selection::traits::Obligation<'tcx, rustc_middle::ty::Predicate<'tcx>>, + >, + ) -> Vec { + obligations + .into_iter() + .flat_map(|obligation| { + obligation + .predicate + .kind() + .as_poly_trait_predicate() + .map(|trait_ref| { + trait_ref + .map_bound(|p| p.trait_ref) + .impl_expr(s, obligation.param_env) + }) + }) + .collect() + } -impl<'tcx> IntoImplExpr<'tcx> for rustc_middle::ty::PolyTraitPredicate<'tcx> { - fn impl_expr>( - &self, - s: &S, - param_env: rustc_middle::ty::ParamEnv<'tcx>, - ) -> ImplExpr { - use rustc_middle::ty::ToPolyTraitRef; - self.to_poly_trait_ref().impl_expr(s, param_env) + pub trait IntoImplExpr<'tcx> { + fn impl_expr>( + &self, + s: &S, + param_env: rustc_middle::ty::ParamEnv<'tcx>, + ) -> ImplExpr; } -} -impl<'tcx> IntoImplExpr<'tcx> for rustc_middle::ty::PolyTraitRef<'tcx> { - #[tracing::instrument(level = "trace", skip(s))] - fn impl_expr>( - &self, - s: &S, - param_env: rustc_middle::ty::ParamEnv<'tcx>, - ) -> ImplExpr { - use rustc_trait_selection::traits::*; - let trait_ref: Binder = self.sinto(s); - let trait_ref = trait_ref.value; - match select_trait_candidate(s, param_env, *self) { - ImplSource::UserDefined(ImplSourceUserDefinedData { - impl_def_id, - args: generics, - nested, - }) => ImplExprAtom::Concrete { - id: impl_def_id.sinto(s), - generics: generics.sinto(s), - } - .with_args(impl_exprs(s, &nested), trait_ref), - ImplSource::Param(nested) => { - use search_clause::TraitPredicateExt; - let tcx = s.base().tcx; - let predicates = &tcx.predicates_defined_on_or_above(s.owner_id()); - let Some((apred, path)) = predicates.into_iter().find_map(|apred| { - apred - .predicate - .to_opt_poly_trait_pred() - .map(|poly_trait_predicate| poly_trait_predicate) - .and_then(|poly_trait_predicate| { - poly_trait_predicate.path_to(s, self.clone(), param_env) + + impl<'tcx> IntoImplExpr<'tcx> for rustc_middle::ty::PolyTraitPredicate<'tcx> { + fn impl_expr>( + &self, + s: &S, + param_env: rustc_middle::ty::ParamEnv<'tcx>, + ) -> ImplExpr { + use rustc_middle::ty::ToPolyTraitRef; + self.to_poly_trait_ref().impl_expr(s, param_env) + } + } + impl<'tcx> IntoImplExpr<'tcx> for rustc_middle::ty::PolyTraitRef<'tcx> { + #[tracing::instrument(level = "trace", skip(s, param_env))] + fn impl_expr>( + &self, + s: &S, + param_env: rustc_middle::ty::ParamEnv<'tcx>, + ) -> ImplExpr { + use rustc_trait_selection::traits::*; + let trait_ref: Binder = self.sinto(s); + let trait_ref = trait_ref.value; + match select_trait_candidate(s, param_env, *self) { + ImplSource::UserDefined(ImplSourceUserDefinedData { + impl_def_id, + args: generics, + nested, + }) => ImplExprAtom::Concrete { + id: impl_def_id.sinto(s), + generics: generics.sinto(s), + } + .with_args(impl_exprs(s, &nested), trait_ref), + ImplSource::Param(nested) => { + let tcx = s.base().tcx; + let predicates = tcx.predicates_defined_on_or_above(s.owner_id()); + let Some((path, apred)) = + search_clause::path_to(&predicates, s, self.clone(), param_env) + else { + supposely_unreachable_fatal!(s, "ImplExprPredNotFound"; { + self, nested, predicates, trait_ref }) - .map(|path| (apred, path)) - }) else { - supposely_unreachable_fatal!(s, "ImplExprPredNotFound"; { - self, nested, predicates, trait_ref - }) - }; - use rustc_middle::ty::ToPolyTraitRef; - let r#trait = apred - .predicate - .to_opt_poly_trait_pred() - .s_unwrap(s) - .to_poly_trait_ref() - .sinto(s); - let path = path.sinto(s); - if apred.is_extra_self_predicate { - ImplExprAtom::SelfImpl { r#trait, path } + }; + + use rustc_middle::ty::ToPolyTraitRef; + let r#trait = apred + .predicate + .as_trait_clause() + .s_unwrap(s) + .to_poly_trait_ref() + .sinto(s); + let path = path.sinto(s); + if apred.is_extra_self_predicate { + ImplExprAtom::SelfImpl { r#trait, path } + .with_args(impl_exprs(s, &nested), trait_ref) + } else { + ImplExprAtom::LocalBound { + predicate_id: apred.predicate.predicate_id(s), + r#trait, + path, + } .with_args(impl_exprs(s, &nested), trait_ref) - } else { - ImplExprAtom::LocalBound { - predicate_id: apred.predicate.predicate_id(s), - r#trait, - path, } - .with_args(impl_exprs(s, &nested), trait_ref) } - } - // We ignore the contained obligations here. For example for `(): Send`, the - // obligations contained would be `[(): Send]`, which leads to an infinite loop. There - // might be important obligation shere inother cases; we'll have to see if that comes - // up. - ImplSource::Builtin(source, _ignored) => { - let atom = match source { - BuiltinImplSource::Object { .. } => ImplExprAtom::Dyn, - _ => ImplExprAtom::Builtin { - r#trait: self.skip_binder().sinto(s), - }, - }; - atom.with_args(vec![], trait_ref) + // We ignore the contained obligations here. For example for `(): Send`, the + // obligations contained would be `[(): Send]`, which leads to an infinite loop. There + // might be important obligation shere inother cases; we'll have to see if that comes + // up. + ImplSource::Builtin(source, _ignored) => { + let atom = match source { + BuiltinImplSource::Object { .. } => ImplExprAtom::Dyn, + _ => ImplExprAtom::Builtin { + r#trait: self.skip_binder().sinto(s), + }, + }; + atom.with_args(vec![], trait_ref) + } } } } -} -/// Given a clause `clause` in the context of some impl. block -/// `impl_did`, susbts correctly `Self` from `clause` and (1) derive a -/// `Clause` and (2) resolve an `ImplExpr`. -pub fn super_clause_to_clause_and_impl_expr<'tcx, S: UnderOwnerState<'tcx>>( - s: &S, - impl_did: rustc_span::def_id::DefId, - clause: rustc_middle::ty::Clause<'tcx>, - span: rustc_span::Span, -) -> Option<(Clause, ImplExpr, Span)> { - let tcx = s.base().tcx; - let impl_trait_ref = tcx - .impl_trait_ref(impl_did) - .map(|binder| rustc_middle::ty::Binder::dummy(binder.instantiate_identity()))?; - let original_predicate_id = { - // We don't want the id of the substituted clause id, but the - // original clause id (with, i.e., `Self`) - let s = &with_owner_id(s.base(), (), (), impl_trait_ref.def_id()); - clause.predicate_id(s) - }; - let new_clause = clause.subst_supertrait(tcx, &impl_trait_ref); - let impl_expr = new_clause - .as_predicate() - .to_opt_poly_trait_pred()? - .impl_expr(s, s.param_env()); - let mut new_clause_no_binder = new_clause.sinto(s); - new_clause_no_binder.id = original_predicate_id; - Some((new_clause_no_binder, impl_expr, span.sinto(s))) -} + /// Given a clause `clause` in the context of some impl. block + /// `impl_did`, susbts correctly `Self` from `clause` and (1) derive a + /// `Clause` and (2) resolve an `ImplExpr`. + pub fn super_clause_to_clause_and_impl_expr<'tcx, S: UnderOwnerState<'tcx>>( + s: &S, + impl_did: rustc_span::def_id::DefId, + clause: rustc_middle::ty::Clause<'tcx>, + span: rustc_span::Span, + ) -> Option<(Clause, ImplExpr, Span)> { + let tcx = s.base().tcx; + let impl_trait_ref = tcx + .impl_trait_ref(impl_did) + .map(|binder| rustc_middle::ty::Binder::dummy(binder.instantiate_identity()))?; + let original_predicate_id = { + // We don't want the id of the substituted clause id, but the + // original clause id (with, i.e., `Self`) + let s = &with_owner_id(s.base(), (), (), impl_trait_ref.def_id()); + clause.predicate_id(s) + }; + let new_clause = clause.instantiate_supertrait(tcx, impl_trait_ref); + let impl_expr = new_clause + .as_predicate() + .as_trait_clause()? + .impl_expr(s, s.param_env()); + let mut new_clause_no_binder = new_clause.sinto(s); + new_clause_no_binder.id = original_predicate_id; + Some((new_clause_no_binder, impl_expr, span.sinto(s))) + } -#[tracing::instrument(level = "trace", skip(s))] -pub fn select_trait_candidate<'tcx, S: UnderOwnerState<'tcx>>( - s: &S, - param_env: rustc_middle::ty::ParamEnv<'tcx>, - trait_ref: rustc_middle::ty::PolyTraitRef<'tcx>, -) -> rustc_trait_selection::traits::Selection<'tcx> { - let tcx = s.base().tcx; - match copy_paste_from_rustc::codegen_select_candidate(tcx, (param_env, trait_ref)) { - Ok(selection) => selection, - Err(error) => fatal!( - s, - "Cannot handle error `{:?}` selecting `{:?}`", - error, - trait_ref - ), + #[tracing::instrument(level = "trace", skip(s, param_env))] + pub fn select_trait_candidate<'tcx, S: UnderOwnerState<'tcx>>( + s: &S, + param_env: rustc_middle::ty::ParamEnv<'tcx>, + trait_ref: rustc_middle::ty::PolyTraitRef<'tcx>, + ) -> rustc_trait_selection::traits::Selection<'tcx> { + let tcx = s.base().tcx; + match copy_paste_from_rustc::codegen_select_candidate(tcx, (param_env, trait_ref)) { + Ok(selection) => selection, + Err(error) => fatal!( + s, + "Cannot handle error `{:?}` selecting `{:?}`", + error, + trait_ref + ), + } } -} -pub mod copy_paste_from_rustc { - use rustc_infer::infer::TyCtxtInferExt; - use rustc_infer::traits::{FulfillmentErrorCode, TraitEngineExt as _}; - use rustc_middle::traits::{CodegenObligationError, DefiningAnchor}; - use rustc_middle::ty::{self, TyCtxt}; - use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; - use rustc_trait_selection::traits::{ - Obligation, ObligationCause, SelectionContext, TraitEngine, TraitEngineExt, Unimplemented, - }; - - /// Attempts to resolve an obligation to an `ImplSource`. The result is - /// a shallow `ImplSource` resolution, meaning that we do not - /// (necessarily) resolve all nested obligations on the impl. Note - /// that type check should guarantee to us that all nested - /// obligations *could be* resolved if we wanted to. - /// - /// This also expects that `trait_ref` is fully normalized. - pub fn codegen_select_candidate<'tcx>( - tcx: TyCtxt<'tcx>, - (param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>), - ) -> Result, CodegenObligationError> { - let trait_ref = tcx.normalize_erasing_regions(param_env, trait_ref); - - // Do the initial selection for the obligation. This yields the - // shallow result we are looking for -- that is, what specific impl. - let infcx = tcx - .infer_ctxt() - .ignoring_regions() - .with_opaque_type_inference(DefiningAnchor::Bubble) - .build(); - //~^ HACK `Bubble` is required for - // this test to pass: type-alias-impl-trait/assoc-projection-ice.rs - let mut selcx = SelectionContext::new(&infcx); - - let obligation_cause = ObligationCause::dummy(); - let obligation = Obligation::new(tcx, obligation_cause, param_env, trait_ref); - - let selection = match selcx.poly_select(&obligation) { - Ok(Some(selection)) => selection, - Ok(None) => return Err(CodegenObligationError::Ambiguity), - Err(Unimplemented) => return Err(CodegenObligationError::Unimplemented), - Err(e) => { - panic!( - "Encountered error `{:?}` selecting `{:?}` during codegen", - e, trait_ref - ) - } + pub mod copy_paste_from_rustc { + use rustc_infer::infer::TyCtxtInferExt; + use rustc_middle::traits::CodegenObligationError; + use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; + use rustc_trait_selection::error_reporting::InferCtxtErrorExt; + use rustc_trait_selection::traits::{ + Obligation, ObligationCause, ObligationCtxt, ScrubbedTraitError, SelectionContext, + Unimplemented, }; - // Currently, we use a fulfillment context to completely resolve - // all nested obligations. This is because they can inform the - // inference of the impl's type parameters. - let mut fulfill_cx = >::new(&infcx); - let impl_source = selection.map(|predicate| { - fulfill_cx.register_predicate_obligation(&infcx, predicate.clone()); - predicate - }); - - // In principle, we only need to do this so long as `impl_source` - // contains unbound type parameters. It could be a slight - // optimization to stop iterating early. - let errors = fulfill_cx.select_all_or_error(&infcx); - if !errors.is_empty() { - // `rustc_monomorphize::collector` assumes there are no type errors. - // Cycle errors are the only post-monomorphization errors possible; emit them now so - // `rustc_ty_utils::resolve_associated_item` doesn't return `None` post-monomorphization. - for err in errors { - if let FulfillmentErrorCode::CodeCycle(cycle) = err.code { - infcx.err_ctxt().report_overflow_obligation_cycle(&cycle); + /// Attempts to resolve an obligation to an `ImplSource`. The result is + /// a shallow `ImplSource` resolution, meaning that we do not + /// (necessarily) resolve all nested obligations on the impl. Note + /// that type check should guarantee to us that all nested + /// obligations *could be* resolved if we wanted to. + /// + /// This also expects that `trait_ref` is fully normalized. + pub fn codegen_select_candidate<'tcx>( + tcx: TyCtxt<'tcx>, + (param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>), + ) -> Result, CodegenObligationError> + { + let trait_ref = tcx.normalize_erasing_regions(param_env, trait_ref); + + // Do the initial selection for the obligation. This yields the + // shallow result we are looking for -- that is, what specific impl. + let infcx = tcx.infer_ctxt().ignoring_regions().build(); + let mut selcx = SelectionContext::new(&infcx); + + let obligation_cause = ObligationCause::dummy(); + let obligation = Obligation::new(tcx, obligation_cause, param_env, trait_ref); + + let selection = match selcx.poly_select(&obligation) { + Ok(Some(selection)) => selection, + Ok(None) => return Err(CodegenObligationError::Ambiguity), + Err(Unimplemented) => return Err(CodegenObligationError::Unimplemented), + Err(e) => { + panic!( + "Encountered error `{:?}` selecting `{:?}` during codegen", + e, trait_ref + ) + } + }; + + // Currently, we use a fulfillment context to completely resolve + // all nested obligations. This is because they can inform the + // inference of the impl's type parameters. + // FIXME(-Znext-solver): Doesn't need diagnostics if new solver. + let ocx = ObligationCtxt::new(&infcx); + let impl_source = selection.map(|obligation| { + ocx.register_obligation(obligation.clone()); + obligation + }); + + // In principle, we only need to do this so long as `impl_source` + // contains unbound type parameters. It could be a slight + // optimization to stop iterating early. + let errors = ocx.select_all_or_error(); + if !errors.is_empty() { + // `rustc_monomorphize::collector` assumes there are no type errors. + // Cycle errors are the only post-monomorphization errors possible; emit them now so + // `rustc_ty_utils::resolve_associated_item` doesn't return `None` post-monomorphization. + for err in errors { + if let ScrubbedTraitError::Cycle(cycle) = err { + infcx.err_ctxt().report_overflow_obligation_cycle(&cycle); + } } + return Err(CodegenObligationError::FulfillmentError); } - return Err(CodegenObligationError::FulfillmentError); - } - let impl_source = infcx.resolve_vars_if_possible(impl_source); - let impl_source = infcx.tcx.erase_regions(impl_source); + let impl_source = infcx.resolve_vars_if_possible(impl_source); + let impl_source = infcx.tcx.erase_regions(impl_source); - // Opaque types may have gotten their hidden types constrained, but we can ignore them safely - // as they will get constrained elsewhere, too. - // (ouz-a) This is required for `type-alias-impl-trait/assoc-projection-ice.rs` to pass - let _ = infcx.take_opaque_types(); + if impl_source.has_infer() { + // Unused lifetimes on an impl get replaced with inference vars, but never resolved, + // causing the return value of a query to contain inference vars. We do not have a concept + // for this and will in fact ICE in stable hashing of the return value. So bail out instead. + infcx.tcx.dcx().has_errors().unwrap(); + return Err(CodegenObligationError::FulfillmentError); + } - Ok(impl_source) + Ok(impl_source) + } } } +#[cfg(feature = "rustc")] +pub use self::rustc::*; diff --git a/frontend/exporter/src/types/copied.rs b/frontend/exporter/src/types/copied.rs index dce59c5c7..4d12199b9 100644 --- a/frontend/exporter/src/types/copied.rs +++ b/frontend/exporter/src/types/copied.rs @@ -1,19 +1,24 @@ use crate::prelude::*; -use crate::rustc_middle::query::Key; + +#[cfg(feature = "rustc")] use rustc_middle::ty; +#[cfg(feature = "rustc")] +use rustc_span::def_id::DefId as RDefId; impl std::hash::Hash for DefId { fn hash(&self, state: &mut H) { let DefId { krate, path, - index: _, // intentionally discarding index + index: _, // intentionally discarding index + is_local: _, // intentionally discarding is_local } = self; krate.hash(state); path.hash(state); } } +#[cfg(feature = "rustc")] impl<'s, S: BaseState<'s>> SInto for rustc_hir::def_id::DefId { fn sinto(&self, s: &S) -> DefId { s.base().exported_def_ids.borrow_mut().insert(self.clone()); @@ -27,10 +32,12 @@ impl<'s, S: BaseState<'s>> SInto for rustc_hir::def_id::DefId { rustc_hir::def_id::CrateNum::as_u32(self.krate), rustc_hir::def_id::DefIndex::as_u32(self.index), ), + is_local: self.is_local(), } } } +#[cfg(feature = "rustc")] impl From<&DefId> for rustc_span::def_id::DefId { fn from<'tcx>(def_id: &DefId) -> Self { let (krate, index) = def_id.index; @@ -41,6 +48,15 @@ impl From<&DefId> for rustc_span::def_id::DefId { } } +// Impl to be able to use hax's `DefId` for many rustc queries. +#[cfg(feature = "rustc")] +impl rustc_middle::query::IntoQueryParam for &DefId { + fn into_query_param(self) -> RDefId { + self.into() + } +} + +#[cfg(feature = "rustc")] impl std::convert::From for Path { fn from(v: DefId) -> Vec { std::iter::once(v.krate) @@ -56,6 +72,7 @@ impl std::convert::From for Path { } pub type GlobalIdent = DefId; +#[cfg(feature = "rustc")] impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_hir::def_id::LocalDefId { fn sinto(&self, st: &S) -> DefId { self.to_def_id().sinto(st) @@ -63,9 +80,8 @@ impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_hir::def_id } /// Reflects [`rustc_middle::thir::LogicalOp`] -#[derive( - AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] #[args(<'a, S>, from: rustc_middle::thir::LogicalOp, state: S as _s)] pub enum LogicalOp { And, @@ -73,9 +89,8 @@ pub enum LogicalOp { } /// Reflects [`rustc_middle::thir::LintLevel`] -#[derive( - AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] #[args(<'slt, S: UnderOwnerState<'slt> + HasThir<'slt>>, from: rustc_middle::thir::LintLevel, state: S as gstate)] pub enum LintLevel { Inherited, @@ -83,9 +98,8 @@ pub enum LintLevel { } /// Reflects [`rustc_ast::ast::AttrStyle`] -#[derive( - AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] #[args(, from: rustc_ast::ast::AttrStyle, state: S as _s)] pub enum AttrStyle { Outer, @@ -93,10 +107,9 @@ pub enum AttrStyle { } /// Reflects [`rustc_ast::ast::Attribute`] -#[derive( - AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] -#[args(<'slt, S: BaseState<'slt>>, from: rustc_ast::ast::Attribute, state: S as gstate)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[args(<'tcx, S: BaseState<'tcx>>, from: rustc_ast::ast::Attribute, state: S as gstate)] pub struct Attribute { pub kind: AttrKind, #[map(x.as_usize())] @@ -105,11 +118,21 @@ pub struct Attribute { pub span: Span, } +/// Reflects [`rustc_attr::InlineAttr`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[args(<'tcx, S: BaseState<'tcx>>, from: rustc_attr::InlineAttr, state: S as _s)] +pub enum InlineAttr { + None, + Hint, + Always, + Never, +} + /// Generic container for decorating items with a type, a span, /// attributes and other meta-data. -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Decorated { pub ty: Ty, pub span: Span, @@ -119,15 +142,18 @@ pub struct Decorated { } /// Reflects [`rustc_middle::mir::UnOp`] -#[derive(AdtInto, Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(AdtInto, Copy, Clone, Debug, JsonSchema)] #[args(<'slt, S: UnderOwnerState<'slt>>, from: rustc_middle::mir::UnOp, state: S as _s)] pub enum UnOp { Not, Neg, + PtrMetadata, } /// Reflects [`rustc_middle::mir::BinOp`] -#[derive(AdtInto, Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(AdtInto, Copy, Clone, Debug, JsonSchema)] #[args(<'slt, S: UnderOwnerState<'slt>>, from: rustc_middle::mir::BinOp, state: S as _s)] pub enum BinOp { // We merge the checked and unchecked variants because in either case overflow is failure. @@ -143,6 +169,9 @@ pub enum BinOp { rustc_middle::mir::BinOp::Mul | rustc_middle::mir::BinOp::MulUnchecked => BinOp::Mul, )] Mul, + AddWithOverflow, + SubWithOverflow, + MulWithOverflow, Div, Rem, BitXor, @@ -162,6 +191,7 @@ pub enum BinOp { Ne, Ge, Gt, + Cmp, Offset, } @@ -169,7 +199,8 @@ pub type Pat = Decorated; pub type Expr = Decorated; /// Reflects [`rustc_middle::mir::BinOp`] -#[derive(AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] #[args(<'tcx, S: UnderOwnerState<'tcx> + HasThir<'tcx>>, from: rustc_middle::middle::region::ScopeData, state: S as gstate)] pub enum ScopeData { Node, @@ -181,37 +212,37 @@ pub enum ScopeData { } /// Reflects [`rustc_middle::mir::BinOp`] -#[derive(AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] #[args(<'tcx, S: UnderOwnerState<'tcx> + HasThir<'tcx>>, from: rustc_middle::middle::region::Scope, state: S as gstate)] pub struct Scope { pub id: ItemLocalId, pub data: ScopeData, } -impl<'tcx, S: UnderOwnerState<'tcx>> SInto - for rustc_middle::mir::ConstantKind<'tcx> -{ +#[cfg(feature = "rustc")] +impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::mir::Const<'tcx> { fn sinto(&self, s: &S) -> ConstantExpr { - use rustc_middle::mir::ConstantKind; + use rustc_middle::mir::Const; let tcx = s.base().tcx; match self { - ConstantKind::Val(const_value, ty) => const_value_to_constant_expr( + Const::Val(const_value, ty) => const_value_to_constant_expr( s, ty.clone(), const_value.clone(), - self.default_span(tcx), + rustc_span::DUMMY_SP, ), - ConstantKind::Ty(c) => c.sinto(s), - ConstantKind::Unevaluated(ucv, ty) => match self.translate_uneval(s, ucv.shrink()) { - TranslateUnevalRes::EvaluatedConstant(c) => c.sinto(s), - TranslateUnevalRes::GlobalName(c) => { - let span = tcx - .def_ident_span(ucv.def) - .unwrap_or_else(|| ucv.def.default_span(tcx)) - .sinto(s); - c.decorate(ty.sinto(s), span) + Const::Ty(_ty, c) => c.sinto(s), + Const::Unevaluated(ucv, _ty) => { + use crate::rustc_middle::query::Key; + let span = tcx + .def_ident_span(ucv.def) + .unwrap_or_else(|| ucv.def.default_span(tcx)); + match self.translate_uneval(s, ucv.shrink(), span) { + TranslateUnevalRes::EvaluatedConstant(c) => c.sinto(s), + TranslateUnevalRes::GlobalName(c) => c, } - }, + } } } } @@ -219,18 +250,21 @@ impl<'tcx, S: UnderOwnerState<'tcx>> SInto // For ConstantKind we merge all the cases (Ty, Val, Unevaluated) into one pub type ConstantKind = ConstantExpr; +#[cfg(feature = "rustc")] impl SInto for rustc_middle::mir::interpret::AllocId { fn sinto(&self, _: &S) -> u64 { self.0.get() } } +#[cfg(feature = "rustc")] impl<'tcx, S: UnderOwnerState<'tcx>> SInto> for rustc_middle::ty::Ty<'tcx> { fn sinto(&self, s: &S) -> Box { Box::new(self.sinto(s)) } } +#[cfg(feature = "rustc")] impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::Ty<'tcx> { fn sinto(&self, s: &S) -> Ty { self.kind().sinto(s) @@ -238,9 +272,8 @@ impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::Ty<'tcx> } /// Reflects [`rustc_hir::hir_id::HirId`] -#[derive( - AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] #[args(<'tcx, S: BaseState<'tcx>>, from: rustc_hir::hir_id::HirId, state: S as gstate)] pub struct HirId { owner: DefId, @@ -249,6 +282,7 @@ pub struct HirId { } // TODO: If not working: See original +#[cfg(feature = "rustc")] impl<'tcx, S: BaseState<'tcx>> SInto for rustc_hir::hir_id::OwnerId { fn sinto(&self, s: &S) -> DefId { self.to_def_id().sinto(s) @@ -256,18 +290,16 @@ impl<'tcx, S: BaseState<'tcx>> SInto for rustc_hir::hir_id::OwnerId { } /// Reflects [`rustc_ast::ast::LitFloatType`] -#[derive( - AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] #[args(<'tcx, S: BaseState<'tcx>>, from: rustc_ast::ast::LitFloatType, state: S as gstate)] pub enum LitFloatType { Suffixed(FloatTy), Unsuffixed, } /// Reflects [`rustc_hir::Movability`] -#[derive( - AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] #[args(<'tcx, S>, from: rustc_hir::Movability, state: S as _s)] pub enum Movability { Static, @@ -275,7 +307,8 @@ pub enum Movability { } /// Reflects [`rustc_middle::infer::canonical::CanonicalTyVarKind`] -#[derive(AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::infer::canonical::CanonicalTyVarKind, state: S as gstate)] pub enum CanonicalTyVarKind { General(UniverseIndex), @@ -284,9 +317,8 @@ pub enum CanonicalTyVarKind { } /// Reflects [`rustc_middle::ty::ParamTy`] -#[derive( - AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::ParamTy, state: S as gstate)] pub struct ParamTy { pub index: u32, @@ -294,19 +326,55 @@ pub struct ParamTy { } /// Reflects [`rustc_middle::ty::ParamConst`] -#[derive( - AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] #[args(, from: rustc_middle::ty::ParamConst, state: S as gstate)] pub struct ParamConst { pub index: u32, pub name: Symbol, } +/// A predicate without `Self`, for use in `dyn Trait`. +/// +/// Reflects [`rustc_middle::ty::ExistentialPredicate`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::ExistentialPredicate<'tcx>, state: S as state)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub enum ExistentialPredicate { + /// E.g. `From`. Note that this isn't `T: From` with a given `T`, this is just + /// `From`. Could be written `?: From`. + Trait(ExistentialTraitRef), + /// E.g. `Iterator::Item = u64`. Could be written `::Item = u64`. + Projection(ExistentialProjection), + /// E.g. `Send`. + AutoTrait(DefId), +} + +/// Reflects [`rustc_type_ir::ExistentialTraitRef`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_type_ir::ExistentialTraitRef>, state: S as state)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct ExistentialTraitRef { + pub def_id: DefId, + pub args: Vec, +} + +/// Reflects [`rustc_type_ir::ExistentialProjection`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_type_ir::ExistentialProjection>, state: S as state)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct ExistentialProjection { + pub def_id: DefId, + pub args: Vec, + pub term: Term, +} + /// Reflects [`rustc_middle::ty::DynKind`] -#[derive( - AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] #[args(, from: rustc_middle::ty::DynKind, state: S as _s)] pub enum DynKind { Dyn, @@ -314,9 +382,8 @@ pub enum DynKind { } /// Reflects [`rustc_middle::ty::BoundTyKind`] -#[derive( - AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::BoundTyKind, state: S as gstate)] pub enum BoundTyKind { Anon, @@ -324,9 +391,8 @@ pub enum BoundTyKind { } /// Reflects [`rustc_middle::ty::BoundTy`] -#[derive( - AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::BoundTy, state: S as gstate)] pub struct BoundTy { pub var: BoundVar, @@ -334,20 +400,18 @@ pub struct BoundTy { } /// Reflects [`rustc_middle::ty::BoundRegionKind`] -#[derive( - AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::BoundRegionKind, state: S as gstate)] pub enum BoundRegionKind { - BrAnon(Option), + BrAnon, BrNamed(DefId, Symbol), BrEnv, } /// Reflects [`rustc_middle::ty::BoundRegion`] -#[derive( - AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::BoundRegion, state: S as gstate)] pub struct BoundRegion { pub var: BoundVar, @@ -362,14 +426,14 @@ pub type PlaceholderConst = Placeholder; pub type PlaceholderType = Placeholder; /// Reflects [`rustc_middle::ty::Placeholder`] -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Placeholder { pub universe: UniverseIndex, pub bound: T, } +#[cfg(feature = "rustc")] impl<'tcx, S: UnderOwnerState<'tcx>, T: SInto, U> SInto> for rustc_middle::ty::Placeholder { @@ -382,7 +446,8 @@ impl<'tcx, S: UnderOwnerState<'tcx>, T: SInto, U> SInto> } /// Reflects [`rustc_middle::infer::canonical::Canonical`] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub struct Canonical { pub max_universe: UniverseIndex, pub variables: Vec, @@ -391,6 +456,7 @@ pub struct Canonical { /// Reflects [`rustc_middle::ty::CanonicalUserType`] pub type CanonicalUserType = Canonical; +#[cfg(feature = "rustc")] impl<'tcx, S: UnderOwnerState<'tcx>, T: SInto, U> SInto> for rustc_middle::infer::canonical::Canonical<'tcx, T> { @@ -404,20 +470,22 @@ impl<'tcx, S: UnderOwnerState<'tcx>, T: SInto, U> SInto> } /// Reflects [`rustc_middle::infer::canonical::CanonicalVarKind`] -#[derive(AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::infer::canonical::CanonicalVarKind<'tcx>, state: S as gstate)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::infer::canonical::CanonicalVarKind>, state: S as gstate)] pub enum CanonicalVarInfo { Ty(CanonicalTyVarKind), PlaceholderTy(PlaceholderType), Region(UniverseIndex), PlaceholderRegion(PlaceholderRegion), - Const(UniverseIndex, Ty), - PlaceholderConst(PlaceholderConst, Ty), + Const(UniverseIndex), + PlaceholderConst(PlaceholderConst), Effect, } /// Reflects [`rustc_middle::ty::UserSelfTy`] -#[derive(AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::UserSelfTy<'tcx>, state: S as gstate)] pub struct UserSelfTy { pub impl_def_id: DefId, @@ -425,7 +493,8 @@ pub struct UserSelfTy { } /// Reflects [`rustc_middle::ty::UserArgs`] -#[derive(AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::UserArgs<'tcx>, state: S as gstate)] pub struct UserArgs { pub args: Vec, @@ -435,7 +504,8 @@ pub struct UserArgs { /// Reflects [`rustc_middle::ty::UserType`]: this is currently /// disabled, and everything is printed as debug in the /// [`UserType::Todo`] variant. -#[derive(AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::UserType<'tcx>, state: S as _s)] pub enum UserType { // TODO: for now, we don't use user types at all. @@ -465,27 +535,50 @@ pub enum UserType { } /// Reflects [`rustc_hir::def::CtorKind`] -#[derive(AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] #[args(, from: rustc_hir::def::CtorKind, state: S as _s)] pub enum CtorKind { Fn, Const, } +/// Reflects [`rustc_hir::def::CtorOf`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] +#[args(, from: rustc_hir::def::CtorOf, state: S as _s)] +pub enum CtorOf { + Struct, + Variant, +} + /// Reflects [`rustc_middle::ty::VariantDiscr`] -#[derive(AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::VariantDiscr, state: S as gstate)] -pub enum VariantDiscr { +pub enum DiscriminantDefinition { Explicit(DefId), Relative(u32), } +/// Reflects [`rustc_middle::ty::util::Discr`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::util::Discr<'tcx>, state: S as gstate)] +pub struct DiscriminantValue { + pub val: u128, + pub ty: Ty, +} + /// Reflects [`rustc_middle::ty::Visibility`] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] -pub enum Visibility { +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub enum Visibility { Public, Restricted(Id), } + +#[cfg(feature = "rustc")] impl, U> SInto> for rustc_middle::ty::Visibility { fn sinto(&self, s: &S) -> Visibility { use rustc_middle::ty::Visibility as T; @@ -497,7 +590,8 @@ impl, U> SInto> for rustc_middle::ty::Visibil } /// Reflects [`rustc_middle::ty::FieldDef`] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub struct FieldDef { pub did: DefId, /// Field definition of [tuple @@ -509,6 +603,7 @@ pub struct FieldDef { pub span: Span, } +#[cfg(feature = "rustc")] impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::FieldDef { fn sinto(&self, s: &S) -> FieldDef { let tcx = s.base().tcx; @@ -538,54 +633,68 @@ impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::Fi } /// Reflects [`rustc_middle::ty::VariantDef`] -#[derive(AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::VariantDef, state: S as s)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub struct VariantDef { pub def_id: DefId, pub ctor: Option<(CtorKind, DefId)>, pub name: Symbol, - pub discr: VariantDiscr, + pub discr_def: DiscriminantDefinition, + pub discr_val: DiscriminantValue, /// The definitions of the fields on this variant. In case of /// [tuple /// structs](https://doc.rust-lang.org/book/ch05-01-defining-structs.html#using-tuple-structs-without-named-fields-to-create-different-types), /// the fields are anonymous, otherwise fields are named. - #[value(self.fields.raw.sinto(s))] pub fields: Vec, /// Span of the definition of the variant - #[value(s.base().tcx.def_span(self.def_id).sinto(s))] pub span: Span, } -/// Reflects [`rustc_middle::ty::EarlyBoundRegion`] -#[derive( - AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::EarlyBoundRegion, state: S as gstate)] -pub struct EarlyBoundRegion { - pub def_id: DefId, +#[cfg(feature = "rustc")] +impl VariantDef { + fn sfrom<'tcx, S: UnderOwnerState<'tcx>>( + s: &S, + def: &ty::VariantDef, + discr_val: ty::util::Discr<'tcx>, + ) -> Self { + VariantDef { + def_id: def.def_id.sinto(s), + ctor: def.ctor.sinto(s), + name: def.name.sinto(s), + discr_def: def.discr.sinto(s), + discr_val: discr_val.sinto(s), + fields: def.fields.raw.sinto(s), + span: s.base().tcx.def_span(def.def_id).sinto(s), + } + } +} + +/// Reflects [`rustc_middle::ty::EarlyParamRegion`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::EarlyParamRegion, state: S as gstate)] +pub struct EarlyParamRegion { pub index: u32, pub name: Symbol, } -/// Reflects [`rustc_middle::ty::FreeRegion`] -#[derive( - AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::FreeRegion, state: S as gstate)] -pub struct FreeRegion { +/// Reflects [`rustc_middle::ty::LateParamRegion`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::LateParamRegion, state: S as gstate)] +pub struct LateParamRegion { pub scope: DefId, pub bound_region: BoundRegionKind, } /// Reflects [`rustc_middle::ty::RegionKind`] -#[derive( - AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::RegionKind<'tcx>, state: S as gstate)] pub enum RegionKind { - ReEarlyBound(EarlyBoundRegion), - ReLateBound(DebruijnIndex, BoundRegion), - ReFree(FreeRegion), + ReEarlyParam(EarlyParamRegion), + ReBound(DebruijnIndex, BoundRegion), + ReLateParam(LateParamRegion), ReStatic, ReVar(RegionVid), RePlaceholder(PlaceholderRegion), @@ -594,9 +703,8 @@ pub enum RegionKind { } /// Reflects [`rustc_middle::ty::Region`] -#[derive( - AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::Region<'tcx>, state: S as s)] pub struct Region { #[value(self.kind().sinto(s))] @@ -604,9 +712,8 @@ pub struct Region { } /// Reflects both [`rustc_middle::ty::GenericArg`] and [`rustc_middle::ty::GenericArgKind`] -#[derive( - AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::GenericArgKind<'tcx>, state: S as s)] pub enum GenericArg { Lifetime(Region), @@ -614,12 +721,14 @@ pub enum GenericArg { Const(ConstantExpr), } +#[cfg(feature = "rustc")] impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::GenericArg<'tcx> { fn sinto(&self, s: &S) -> GenericArg { self.unpack().sinto(s) } } +#[cfg(feature = "rustc")] impl<'tcx, S: UnderOwnerState<'tcx>> SInto> for rustc_middle::ty::GenericArgsRef<'tcx> { @@ -631,16 +740,16 @@ impl<'tcx, S: UnderOwnerState<'tcx>> SInto> /// Reflects both [`rustc_middle::ty::GenericArg`] and [`rustc_middle::ty::GenericArgKind`] #[derive(AdtInto)] #[args(<'tcx, S: BaseState<'tcx>>, from: rustc_ast::ast::LitIntType, state: S as gstate)] -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum LitIntType { Signed(IntTy), Unsigned(UintTy), Unsuffixed, } -#[derive(AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] #[args(<'tcx, S: ExprState<'tcx>>, from: rustc_middle::thir::FruInfo<'tcx>, state: S as gstate)] /// Field Record Update (FRU) informations, this reflects [`rustc_middle::thir::FruInfo`] pub struct FruInfo { @@ -650,21 +759,24 @@ pub struct FruInfo { } /// A field expression: a field name along with a value -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub struct FieldExpr { pub field: DefId, pub value: Expr, } /// A field pattern: a field name along with a pattern -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub struct FieldPat { pub field: DefId, pub pattern: Pat, } /// Reflects [`rustc_middle::thir::AdtExpr`] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub struct AdtExpr { pub info: VariantInformations, pub user_ty: Option, @@ -672,6 +784,7 @@ pub struct AdtExpr { pub base: Option, } +#[cfg(feature = "rustc")] impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::AdtExpr<'tcx> { fn sinto(&self, s: &S) -> AdtExpr { let variants = self.adt_def.variants(); @@ -693,16 +806,16 @@ impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::AdtExpr } /// Reflects [`rustc_span::Loc`] -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct Loc { pub line: usize, pub col: usize, } /// Reflects [`rustc_span::hygiene::DesugaringKind`] -#[derive(AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] #[args(, from: rustc_span::hygiene::DesugaringKind, state: S as _s)] pub enum DesugaringKind { CondTemporary, @@ -714,10 +827,12 @@ pub enum DesugaringKind { Await, ForLoop, WhileLoop, + BoundModifier, } /// Reflects [`rustc_span::hygiene::AstPass`] -#[derive(AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] #[args(, from: rustc_span::hygiene::AstPass, state: S as _s)] pub enum AstPass { StdImports, @@ -726,7 +841,8 @@ pub enum AstPass { } /// Reflects [`rustc_span::hygiene::MacroKind`] -#[derive(AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] #[args(, from: rustc_span::hygiene::MacroKind, state: S as _s)] pub enum MacroKind { Bang, @@ -737,7 +853,8 @@ pub enum MacroKind { /// Reflects [`rustc_span::hygiene::ExpnKind`] #[derive(AdtInto)] #[args(<'tcx, S: BaseState<'tcx>>, from: rustc_span::hygiene::ExpnKind, state: S as gstate)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub enum ExpnKind { Root, Macro(MacroKind, Symbol), @@ -748,7 +865,8 @@ pub enum ExpnKind { /// Reflects [`rustc_span::edition::Edition`] #[derive(AdtInto)] #[args(, from: rustc_span::edition::Edition, state: S as _s)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub enum Edition { Edition2015, Edition2018, @@ -759,7 +877,8 @@ pub enum Edition { /// Reflects [`rustc_span::hygiene::ExpnData`] #[derive(AdtInto)] #[args(<'tcx, S: BaseState<'tcx>>, from: rustc_span::hygiene::ExpnData, state: S as state)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub struct ExpnData { pub kind: ExpnKind, // pub parent: Box, @@ -770,24 +889,69 @@ pub struct ExpnData { pub edition: Edition, pub macro_def_id: Option, pub parent_module: Option, - pub allow_internal_unsafe: bool, pub local_inner_macros: bool, - pub collapse_debuginfo: bool, } /// Reflects [`rustc_span::Span`] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, Eq, Ord)] +#[derive(::serde::Serialize, ::serde::Deserialize, Clone, Debug, JsonSchema, Eq, Ord)] pub struct Span { pub lo: Loc, pub hi: Loc, pub filename: FileName, /// Original rustc span; can be useful for reporting rustc /// diagnostics (this is used in Charon) + #[cfg(feature = "rustc")] #[serde(skip)] pub rust_span_data: Option, + #[cfg(not(feature = "rustc"))] + #[serde(skip)] + pub rust_span_data: Option<()>, // expn_backtrace: Vec, } +/// We need to define manual `impl`s of `Span`: we want to skip the +/// field `rust_span_data`. The derive macros from `bincode` don't +/// allow that, see https://github.com/bincode-org/bincode/issues/452. +const _: () = { + impl bincode::Encode for Span { + fn encode( + &self, + encoder: &mut E, + ) -> core::result::Result<(), bincode::error::EncodeError> { + bincode::Encode::encode(&self.lo, encoder)?; + bincode::Encode::encode(&self.hi, encoder)?; + bincode::Encode::encode(&self.filename, encoder)?; + Ok(()) + } + } + + impl bincode::Decode for Span { + fn decode( + decoder: &mut D, + ) -> core::result::Result { + Ok(Self { + lo: bincode::Decode::decode(decoder)?, + hi: bincode::Decode::decode(decoder)?, + filename: bincode::Decode::decode(decoder)?, + rust_span_data: None, + }) + } + } + + impl<'de> bincode::BorrowDecode<'de> for Span { + fn borrow_decode>( + decoder: &mut D, + ) -> core::result::Result { + Ok(Self { + lo: bincode::BorrowDecode::borrow_decode(decoder)?, + hi: bincode::BorrowDecode::borrow_decode(decoder)?, + filename: bincode::BorrowDecode::borrow_decode(decoder)?, + rust_span_data: None, + }) + } + } +}; + const _: () = { // `rust_span_data` is a metadata that should *not* be taken into // account while hashing or comparing @@ -818,6 +982,7 @@ const _: () = { } }; +#[cfg(feature = "rustc")] impl Into for rustc_span::Loc { fn into(self) -> Loc { Loc { @@ -827,6 +992,7 @@ impl Into for rustc_span::Loc { } } +#[cfg(feature = "rustc")] impl<'tcx, S: BaseState<'tcx>> SInto for rustc_span::Span { fn sinto(&self, s: &S) -> Span { let set: crate::state::ExportedSpans = s.base().exported_spans; @@ -836,12 +1002,14 @@ impl<'tcx, S: BaseState<'tcx>> SInto for rustc_span::Span { } /// Reflects [`rustc_middle::thir::LocalVarId`] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub struct LocalIdent { pub name: String, pub id: HirId, } +#[cfg(feature = "rustc")] impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::thir::LocalVarId { fn sinto(&self, s: &S) -> LocalIdent { LocalIdent { @@ -860,11 +1028,13 @@ impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::thir } /// Reflects [`rustc_span::source_map::Spanned`] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub struct Spanned { pub node: T, pub span: Span, } +#[cfg(feature = "rustc")] impl<'s, S: UnderOwnerState<'s>, T: SInto, U> SInto> for rustc_span::source_map::Spanned { @@ -883,9 +1053,8 @@ impl<'tcx, S> SInto for PathBuf { } /// Reflects [`rustc_span::RealFileName`] -#[derive( - AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema, PartialEq, Eq, Hash, PartialOrd, Ord)] #[args(, from: rustc_span::RealFileName, state: S as _s)] pub enum RealFileName { LocalPath(PathBuf), @@ -895,6 +1064,7 @@ pub enum RealFileName { }, } +#[cfg(feature = "rustc")] impl SInto for rustc_data_structures::stable_hasher::Hash64 { fn sinto(&self, _: &S) -> u64 { self.as_u64() @@ -904,16 +1074,14 @@ impl SInto for rustc_data_structures::stable_hasher::Hash64 { /// Reflects [`rustc_span::FileName`] #[derive(AdtInto)] #[args(, from: rustc_span::FileName, state: S as gstate)] -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, PartialEq, Eq, Hash, PartialOrd, Ord)] pub enum FileName { Real(RealFileName), QuoteExpansion(u64), Anon(u64), MacroExpansion(u64), ProcMacroSourceCode(u64), - CfgSpec(u64), CliCrateAttr(u64), Custom(String), // #[map(FileName::DocTest(x.0.to_str().unwrap().into()))] @@ -922,10 +1090,38 @@ pub enum FileName { InlineAsm(u64), } +impl FileName { + pub fn to_string(&self) -> String { + match self { + Self::Real(RealFileName::LocalPath(path)) + | Self::Real(RealFileName::Remapped { + local_path: Some(path), + .. + }) + | Self::Real(RealFileName::Remapped { + virtual_name: path, .. + }) => format!("{}", path.display()), + _ => format!("{:?}", self), + } + } + pub fn to_path(&self) -> Option<&std::path::Path> { + match self { + Self::Real(RealFileName::LocalPath(path)) + | Self::Real(RealFileName::Remapped { + local_path: Some(path), + .. + }) + | Self::Real(RealFileName::Remapped { + virtual_name: path, .. + }) => Some(path), + _ => None, + } + } +} + /// Reflects partially [`rustc_middle::ty::InferTy`] -#[derive( - AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] #[args(<'tcx, S>, from: rustc_middle::ty::InferTy, state: S as gstate)] pub enum InferTy { #[custom_arm(FROM_TYPE::TyVar(..) => TO_TYPE::TyVar,)] @@ -940,7 +1136,8 @@ pub enum InferTy { } /// Reflects [`rustc_middle::thir::BlockSafety`] -#[derive(AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] #[args(<'tcx, S>, from: rustc_middle::thir::BlockSafety, state: S as _s)] pub enum BlockSafety { Safe, @@ -950,42 +1147,54 @@ pub enum BlockSafety { } /// Reflects [`rustc_middle::thir::Block`] -#[derive(AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] #[args(<'tcx, S: ExprState<'tcx>>, from: rustc_middle::thir::Block, state: S as gstate)] pub struct Block { pub targeted_by_break: bool, pub region_scope: Scope, - pub opt_destruction_scope: Option, pub span: Span, pub stmts: Vec, pub expr: Option, pub safety_mode: BlockSafety, } -/// Reflects [`rustc_middle::thir::BindingMode`] +/// Reflects [`rustc_ast::ast::BindingMode`] #[derive(AdtInto)] -#[args(, from: rustc_middle::thir::BindingMode, state: S as s)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] -pub enum BindingMode { - ByValue, - ByRef(BorrowKind), +#[args(, from: rustc_ast::ast::BindingMode, state: S as s)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub struct BindingMode { + #[value(self.0.sinto(s))] + pub by_ref: ByRef, + #[value(self.1.sinto(s))] + pub mutability: Mutability, +} + +/// Reflects [`rustc_ast::ast::ByRef`] +#[derive(AdtInto)] +#[args(, from: rustc_ast::ast::ByRef, state: S as s)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub enum ByRef { + Yes(Mutability), + No, } /// Reflects [`rustc_middle::thir::Stmt`] #[derive(AdtInto)] #[args(<'tcx, S: ExprState<'tcx>>, from: rustc_middle::thir::Stmt<'tcx>, state: S as s)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub struct Stmt { pub kind: StmtKind, - pub opt_destruction_scope: Option, } /// Reflects [`rustc_ast::token::Delimiter`] #[derive(AdtInto)] #[args(, from: rustc_ast::token::Delimiter, state: S as _s)] -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum Delimiter { Parenthesis, Brace, @@ -996,31 +1205,29 @@ pub enum Delimiter { /// Reflects [`rustc_ast::tokenstream::TokenTree`] #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_ast::tokenstream::TokenTree, state: S as s)] -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum TokenTree { Token(Token, Spacing), - Delimited(DelimSpan, Delimiter, TokenStream), + Delimited(DelimSpan, DelimSpacing, Delimiter, TokenStream), } /// Reflects [`rustc_ast::tokenstream::Spacing`] #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_ast::tokenstream::Spacing, state: S as _s)] -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum Spacing { Alone, Joint, + JointHidden, } /// Reflects [`rustc_ast::token::BinOpToken`] #[derive(AdtInto)] #[args(, from: rustc_ast::token::BinOpToken, state: S as _s)] -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum BinOpToken { Plus, Minus, @@ -1037,9 +1244,8 @@ pub enum BinOpToken { /// Reflects [`rustc_ast::token::TokenKind`] #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_ast::token::TokenKind, state: S as gstate)] -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum TokenKind { Eq, Lt, @@ -1062,7 +1268,6 @@ pub enum TokenKind { Comma, Semi, Colon, - ModSep, RArrow, LArrow, FatArrow, @@ -1082,12 +1287,21 @@ pub enum TokenKind { Todo(String), } +#[cfg(feature = "rustc")] +impl SInto for rustc_ast::token::IdentIsRaw { + fn sinto(&self, _s: &S) -> bool { + match self { + Self::Yes => true, + Self::No => false, + } + } +} + /// Reflects [`rustc_ast::token::Token`] #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_ast::token::Token, state: S as gstate)] -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Token { pub kind: TokenKind, pub span: Span, @@ -1096,9 +1310,8 @@ pub struct Token { /// Reflects [`rustc_ast::ast::DelimArgs`] #[derive(AdtInto)] #[args(, from: rustc_ast::ast::DelimArgs, state: S as gstate)] -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct DelimArgs { pub dspan: DelimSpan, pub delim: Delimiter, @@ -1108,9 +1321,8 @@ pub struct DelimArgs { /// Reflects [`rustc_ast::ast::MacCall`] #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_ast::ast::MacCall, state: S as gstate)] -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct MacCall { #[map(x.segments.iter().map(|rustc_ast::ast::PathSegment{ident, ..}| ident.as_str().into()).collect())] pub path: Path, @@ -1121,28 +1333,28 @@ pub struct MacCall { /// string. If you need to reshape that into Rust tokens or construct, /// please use, e.g., `syn`. pub type TokenStream = String; +#[cfg(feature = "rustc")] impl<'t, S> SInto for rustc_ast::tokenstream::TokenStream { fn sinto(&self, _: &S) -> String { rustc_ast_pretty::pprust::tts_to_string(self) } } +#[cfg(feature = "rustc")] impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::BlockId { fn sinto(&self, s: &S) -> Block { s.thir().blocks[*self].sinto(s) } } +#[cfg(feature = "rustc")] impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::StmtId { fn sinto(&self, s: &S) -> Stmt { s.thir().stmts[*self].sinto(s) } } -/// While translating expressions, we expect to always have a THIR -/// body and an `owner_id` in the state -pub trait ExprState<'tcx> = UnderOwnerState<'tcx> + HasThir<'tcx>; - +#[cfg(feature = "rustc")] impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::Expr<'tcx> { fn sinto(&self, s: &S) -> Expr { let (hir_id, attributes) = self.hir_id_and_attributes(s); @@ -1153,29 +1365,31 @@ impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::Expr<'tcx> Some(contents) => contents, None => match kind { // Introduce intermediate `Cast` from `T` to `U` when casting from a `#[repr(T)]` enum to `U` - rustc_middle::thir::ExprKind::Cast { source } - if let rustc_middle::ty::TyKind::Adt(def, _) = - s.thir().exprs[source].ty.kind() => - { - let tcx = s.base().tcx; - let contents = kind.sinto(s); - use crate::rustc_middle::ty::util::IntTypeExt; - let repr_type = tcx - .repr_options_of_def(def.did()) - .discr_type() - .to_ty(s.base().tcx); - if repr_type == ty { - contents - } else { - ExprKind::Cast { - source: Decorated { - ty: repr_type.sinto(s), - span: span.sinto(s), - contents: Box::new(contents), - hir_id, - attributes: vec![], - }, + rustc_middle::thir::ExprKind::Cast { source } => { + if let rustc_middle::ty::TyKind::Adt(def, _) = s.thir().exprs[source].ty.kind() + { + let tcx = s.base().tcx; + let contents = kind.sinto(s); + use crate::rustc_middle::ty::util::IntTypeExt; + let repr_type = tcx + .repr_options_of_def(def.did().expect_local()) + .discr_type() + .to_ty(s.base().tcx); + if repr_type == ty { + contents + } else { + ExprKind::Cast { + source: Decorated { + ty: repr_type.sinto(s), + span: span.sinto(s), + contents: Box::new(contents), + hir_id, + attributes: vec![], + }, + } } + } else { + kind.sinto(s) } } rustc_middle::thir::ExprKind::NonHirLiteral { lit, .. } => { @@ -1210,7 +1424,11 @@ impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::Expr<'tcx> supposely_unreachable_fatal!(s[span], "PhantomDataNotAdt"; {kind, ty}) }; let adt_def = AdtExpr { - info: get_variant_information(def, rustc_abi::FIRST_VARIANT, s), + info: get_variant_information( + def, + rustc_target::abi::FIRST_VARIANT, + s, + ), user_ty: None, base: None, fields: vec![], @@ -1286,12 +1504,14 @@ impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::Expr<'tcx> } } +#[cfg(feature = "rustc")] impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::ExprId { fn sinto(&self, s: &S) -> Expr { s.thir().exprs[*self].sinto(s) } } +#[cfg(feature = "rustc")] impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::Pat<'tcx> { fn sinto(&self, s: &S) -> Pat { let rustc_middle::thir::Pat { span, kind, ty } = self; @@ -1331,6 +1551,7 @@ impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::Pat<'tcx> { } } +#[cfg(feature = "rustc")] impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::ArmId { fn sinto(&self, s: &S) -> Arm { s.thir().arms[*self].sinto(s) @@ -1340,9 +1561,8 @@ impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::ArmId { /// Reflects [`rustc_type_ir::IntTy`] #[derive(AdtInto)] #[args(, from: rustc_type_ir::IntTy, state: S as _s)] -#[derive( - Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Copy, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum IntTy { Isize, I8, @@ -1355,24 +1575,29 @@ pub enum IntTy { /// Reflects [`rustc_type_ir::FloatTy`] #[derive(AdtInto)] #[args(, from: rustc_type_ir::FloatTy, state: S as _s)] -#[derive( - Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Copy, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum FloatTy { + F16, F32, F64, + F128, } +#[cfg(feature = "rustc")] impl<'tcx, S> SInto for rustc_ast::ast::FloatTy { fn sinto(&self, _: &S) -> FloatTy { use rustc_ast::ast::FloatTy as T; match self { + T::F16 => FloatTy::F16, T::F32 => FloatTy::F32, T::F64 => FloatTy::F64, + T::F128 => FloatTy::F128, } } } +#[cfg(feature = "rustc")] impl<'tcx, S> SInto for rustc_ast::ast::IntTy { fn sinto(&self, _: &S) -> IntTy { use rustc_ast::ast::IntTy as T; @@ -1386,6 +1611,7 @@ impl<'tcx, S> SInto for rustc_ast::ast::IntTy { } } } +#[cfg(feature = "rustc")] impl<'tcx, S> SInto for rustc_ast::ast::UintTy { fn sinto(&self, _: &S) -> UintTy { use rustc_ast::ast::UintTy as T; @@ -1403,9 +1629,8 @@ impl<'tcx, S> SInto for rustc_ast::ast::UintTy { /// Reflects [`rustc_type_ir::UintTy`] #[derive(AdtInto)] #[args(, from: rustc_type_ir::UintTy, state: S as _s)] -#[derive( - Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Copy, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum UintTy { Usize, U8, @@ -1446,14 +1671,14 @@ impl ToString for UintTy { /// Reflects [`rustc_middle::ty::TypeAndMut`] #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::TypeAndMut<'tcx>, state: S as gstate)] -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct TypeAndMut { pub ty: Box, pub mutbl: Mutability, } +#[cfg(feature = "rustc")] impl> SInto> for rustc_middle::ty::List { fn sinto(&self, s: &S) -> Vec { self.iter().map(|x| x.sinto(s)).collect() @@ -1462,33 +1687,52 @@ impl> SInto> for rustc_middle::ty::List { /// Reflects [`rustc_middle::ty::GenericParamDef`] #[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::GenericParamDef, state: S as state)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::GenericParamDef, state: S as s)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub struct GenericParamDef { pub name: Symbol, pub def_id: DefId, pub index: u32, pub pure_wrt_drop: bool, + #[value( + match self.kind { + ty::GenericParamDefKind::Lifetime => GenericParamDefKind::Lifetime, + ty::GenericParamDefKind::Type { has_default, synthetic } => GenericParamDefKind::Type { has_default, synthetic }, + ty::GenericParamDefKind::Const { has_default, is_host_effect, .. } => { + let ty = s.base().tcx.type_of(self.def_id).instantiate_identity().sinto(s); + GenericParamDefKind::Const { has_default, is_host_effect, ty } + }, + } + )] pub kind: GenericParamDefKind, } /// Reflects [`rustc_middle::ty::GenericParamDefKind`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::GenericParamDefKind, state: S as state)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub enum GenericParamDefKind { Lifetime, - Type { has_default: bool, synthetic: bool }, - Const { has_default: bool }, + Type { + has_default: bool, + synthetic: bool, + }, + Const { + has_default: bool, + is_host_effect: bool, + ty: Ty, + }, } /// Reflects [`rustc_middle::ty::Generics`] #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::Generics, state: S as state)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub struct TyGenerics { pub parent: Option, pub parent_count: usize, + #[from(own_params)] pub params: Vec, // pub param_def_id_to_index: FxHashMap, pub has_self: bool, @@ -1496,10 +1740,9 @@ pub struct TyGenerics { } /// This type merges the information from -/// `rustc_type_ir::sty::AliasKind` and `rustc_middle::ty::AliasTy` -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +/// `rustc_type_ir::AliasKind` and `rustc_middle::ty::AliasTy` +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Alias { pub kind: AliasKind, pub args: Vec, @@ -1507,9 +1750,8 @@ pub struct Alias { } /// Reflects [`rustc_middle::ty::AliasKind`] -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum AliasKind { /// The projection of a trait type: `>::Type<...>` Projection { @@ -1526,14 +1768,15 @@ pub enum AliasKind { Weak, } +#[cfg(feature = "rustc")] impl Alias { #[tracing::instrument(level = "trace", skip(s))] fn from<'tcx, S: BaseState<'tcx> + HasOwnerId>( s: &S, - alias_kind: &rustc_type_ir::sty::AliasKind, + alias_kind: &rustc_type_ir::AliasTyKind, alias_ty: &rustc_middle::ty::AliasTy<'tcx>, ) -> Self { - use rustc_type_ir::sty::AliasKind as RustAliasKind; + use rustc_type_ir::AliasTyKind as RustAliasKind; let kind = match alias_kind { RustAliasKind::Projection => { use rustc_middle::ty::{Binder, EarlyBinder, TypeVisitableExt}; @@ -1548,12 +1791,12 @@ impl Alias { let trait_ref_and_generics = alias_ty.trait_ref_and_own_args(tcx); let rebased_generics = alias_ty.rebase_inherent_args_onto_impl(alias_ty.args, tcx); - let norm_rebased_generics = tcx.try_subst_and_normalize_erasing_regions( + let norm_rebased_generics = tcx.try_instantiate_and_normalize_erasing_regions( rebased_generics, s.param_env(), EarlyBinder::bind(trait_ref), ); - let norm_generics = tcx.try_subst_and_normalize_erasing_regions( + let norm_generics = tcx.try_instantiate_and_normalize_erasing_regions( alias_ty.args, s.param_env(), EarlyBinder::bind(trait_ref), @@ -1599,9 +1842,8 @@ impl Alias { /// Reflects [`rustc_middle::ty::TyKind`] #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::TyKind<'tcx>, state: S as state)] -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum Ty { Bool, Char, @@ -1617,7 +1859,7 @@ pub enum Ty { }, FROM_TYPE::Closure (_defid, generics) => { let sig = generics.as_closure().sig(); - let sig = state.base().tcx.signature_unclosure(sig, rustc_hir::Unsafety::Normal); + let sig = state.base().tcx.signature_unclosure(sig, rustc_hir::Safety::Safe); arrow_of_sig(&sig, state) }, )] @@ -1628,7 +1870,11 @@ pub enum Ty { rustc_middle::ty::TyKind::Adt(adt_def, generics) => { let def_id = adt_def.did().sinto(state); let generic_args: Vec = generics.sinto(state); - let trait_refs = solve_item_traits(state, state.param_env(), adt_def.did(), generics, None); + let trait_refs = if state.base().ty_alias_mode { + vec![] + } else { + solve_item_traits(state, state.param_env(), adt_def.did(), generics, None) + }; Ty::Adt { def_id, generic_args, trait_refs } }, )] @@ -1644,10 +1890,10 @@ pub enum Ty { Str, Array(Box, #[map(Box::new(x.sinto(state)))] Box), Slice(Box), - RawPtr(TypeAndMut), + RawPtr(Box, Mutability), Ref(Region, Box, Mutability), Dynamic(Vec>, Region, DynKind), - Generator(DefId, Vec, Movability), + Coroutine(DefId, Vec), Never, Tuple(Vec), #[custom_arm( @@ -1669,7 +1915,8 @@ pub enum Ty { /// Reflects [`rustc_middle::thir::StmtKind`] #[derive(AdtInto)] #[args(<'tcx, S: ExprState<'tcx>>, from: rustc_middle::thir::StmtKind<'tcx>, state: S as gstate)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub enum StmtKind { Expr { scope: Scope, @@ -1691,7 +1938,8 @@ pub enum StmtKind { /// Reflects [`rustc_middle::ty::Variance`] #[derive(AdtInto)] #[args(, from: rustc_middle::ty::Variance, state: S as _s)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub enum Variance { Covariant, Invariant, @@ -1702,7 +1950,8 @@ pub enum Variance { /// Reflects [`rustc_middle::ty::CanonicalUserTypeAnnotation`] #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::CanonicalUserTypeAnnotation<'tcx>, state: S as gstate)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub struct CanonicalUserTypeAnnotation { pub user_ty: CanonicalUserType, pub span: Span, @@ -1712,7 +1961,8 @@ pub struct CanonicalUserTypeAnnotation { /// Reflects [`rustc_middle::thir::Ascription`] #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx> + HasThir<'tcx>>, from: rustc_middle::thir::Ascription<'tcx>, state: S as gstate)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub struct Ascription { pub annotation: CanonicalUserTypeAnnotation, pub variance: Variance, @@ -1721,7 +1971,8 @@ pub struct Ascription { /// Reflects [`rustc_hir::RangeEnd`] #[derive(AdtInto)] #[args(, from: rustc_hir::RangeEnd, state: S as _s)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub enum RangeEnd { Included, Excluded, @@ -1730,15 +1981,28 @@ pub enum RangeEnd { /// Reflects [`rustc_middle::thir::PatRange`] #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx> + HasThir<'tcx>>, from: rustc_middle::thir::PatRange<'tcx>, state: S as state)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub struct PatRange { - pub lo: ConstantExpr, - pub hi: ConstantExpr, + pub lo: PatRangeBoundary, + pub hi: PatRangeBoundary, pub end: RangeEnd, } +/// Reflects [`rustc_middle::thir::PatRangeBoundary`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx> + HasThir<'tcx>>, from: rustc_middle::thir::PatRangeBoundary<'tcx>, state: S as state)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub enum PatRangeBoundary { + Finite(ConstantExpr), + NegInfinity, + PosInfinity, +} + /// Reflects [`rustc_middle::ty::AdtKind`] -#[derive(AdtInto, Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(AdtInto, Copy, Clone, Debug, JsonSchema)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::AdtKind, state: S as _s)] pub enum AdtKind { Struct, @@ -1749,7 +2013,8 @@ pub enum AdtKind { // This comes from MIR // TODO: add the generics and the predicates /// Reflects [`rustc_middle::ty::AdtDef`] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub struct AdtDef { pub did: DefId, pub adt_kind: AdtKind, @@ -1759,7 +2024,8 @@ pub struct AdtDef { } /// Reflects [`rustc_middle::ty::ReprOptions`] -#[derive(AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::ReprOptions, state: S as s)] pub struct ReprOptions { pub int: Option, @@ -1774,12 +2040,30 @@ pub struct ReprOptions { pub field_shuffle_seed: u64, } +#[cfg(feature = "rustc")] impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::AdtDef<'tcx> { fn sinto(&self, s: &S) -> AdtDef { + let variants = self + .variants() + .iter_enumerated() + .map(|(variant_idx, variant)| { + let discr = if self.is_enum() { + self.discriminant_for_variant(s.base().tcx, variant_idx) + } else { + // Structs and unions have a single variant. + assert_eq!(variant_idx.index(), 0); + rustc_middle::ty::util::Discr { + val: 0, + ty: s.base().tcx.types.isize, + } + }; + VariantDef::sfrom(s, variant, discr) + }) + .collect(); AdtDef { did: self.did().sinto(s), adt_kind: self.adt_kind().sinto(s), - variants: self.variants().sinto(s), + variants, flags: self.flags().sinto(s), repr: self.repr().sinto(s), } @@ -1787,9 +2071,8 @@ impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::AdtD } /// Describe a variant -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct VariantInformations { pub type_namespace: DefId, @@ -1811,7 +2094,8 @@ pub struct VariantInformations { /// Reflects [`rustc_middle::thir::PatKind`] #[derive(AdtInto)] #[args(<'tcx, S: ExprState<'tcx>>, from: rustc_middle::thir::PatKind<'tcx>, state: S as gstate)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] #[append(rustc_middle::thir::PatKind::Leaf {..} => fatal!(gstate, "PatKind::Leaf: should never come up"),)] pub enum PatKind { Wild, @@ -1820,11 +2104,10 @@ pub enum PatKind { subpattern: Pat, }, #[custom_arm( - rustc_middle::thir::PatKind::Binding {mutability, name, mode, var, ty, subpattern, is_primary} => { + rustc_middle::thir::PatKind::Binding {name, mode, var, ty, subpattern, is_primary} => { let local_ctx = gstate.base().local_ctx; local_ctx.borrow_mut().vars.insert(var.clone(), name.to_string()); PatKind::Binding { - mutability: mutability.sinto(gstate), mode: mode.sinto(gstate), var: var.sinto(gstate), ty: ty.sinto(gstate), @@ -1834,7 +2117,6 @@ pub enum PatKind { } )] Binding { - mutability: Mutability, mode: BindingMode, var: LocalIdent, // name VS var? TODO ty: Ty, @@ -1870,9 +2152,16 @@ pub enum PatKind { Deref { subpattern: Pat, }, + DerefPattern { + subpattern: Pat, + }, Constant { value: ConstantExpr, }, + InlineConstant { + def: DefId, + subpattern: Pat, + }, Range(PatRange), Slice { prefix: Vec, @@ -1887,24 +2176,18 @@ pub enum PatKind { Or { pats: Vec, }, -} - -/// Reflects [`rustc_middle::thir::Guard`] -#[derive(AdtInto)] -#[args(<'tcx, S: ExprState<'tcx>>, from: rustc_middle::thir::Guard<'tcx>, state: S as gstate)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] -pub enum Guard { - If(Expr), - IfLet(Pat, Expr), + Never, + Error(ErrorGuaranteed), } /// Reflects [`rustc_middle::thir::Arm`] #[derive(AdtInto)] #[args(<'tcx, S: ExprState<'tcx>>, from: rustc_middle::thir::Arm<'tcx>, state: S as gstate)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub struct Arm { pub pattern: Pat, - pub guard: Option, + pub guard: Option, pub body: Expr, pub lint_level: LintLevel, pub scope: Scope, @@ -1913,25 +2196,25 @@ pub struct Arm { attributes: Vec, } -/// Reflects [`rustc_hir::Unsafety`] +/// Reflects [`rustc_hir::Safety`] #[derive(AdtInto)] -#[args(, from: rustc_hir::Unsafety, state: S as _s)] -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] -pub enum Unsafety { +#[args(, from: rustc_hir::Safety, state: S as _s)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub enum Safety { Unsafe, - Normal, + Safe, } /// Reflects [`rustc_middle::ty::adjustment::PointerCoercion`] #[derive(AdtInto)] #[args(, from: rustc_middle::ty::adjustment::PointerCoercion, state: S as gstate)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub enum PointerCoercion { ReifyFnPointer, UnsafeFnPointer, - ClosureFnPointer(Unsafety), + ClosureFnPointer(Safety), MutToConstPointer, ArrayToPointer, Unsize, @@ -1940,33 +2223,45 @@ pub enum PointerCoercion { /// Reflects [`rustc_middle::mir::BorrowKind`] #[derive(AdtInto)] #[args(, from: rustc_middle::mir::BorrowKind, state: S as gstate)] -#[derive( - Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Copy, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum BorrowKind { Shared, - Shallow, + Fake(FakeBorrowKind), Mut { kind: MutBorrowKind }, } /// Reflects [`rustc_middle::mir::MutBorrowKind`] #[derive(AdtInto)] #[args(, from: rustc_middle::mir::MutBorrowKind, state: S as _s)] -#[derive( - Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Copy, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum MutBorrowKind { Default, TwoPhaseBorrow, ClosureCapture, } +/// Reflects [`rustc_middle::mir::FakeBorrowKind`] +#[derive(AdtInto)] +#[args(, from: rustc_middle::mir::FakeBorrowKind, state: S as _s)] +#[derive_group(Serializers)] +#[derive(Copy, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub enum FakeBorrowKind { + /// A shared (deep) borrow. Data must be immutable and is aliasable. + Deep, + /// The immediately borrowed place must be immutable, but projections from + /// it don't need to be. This is used to prevent match guards from replacing + /// the scrutinee. For example, a fake borrow of `a.b` doesn't + /// conflict with a mutable borrow of `a.b.c`. + Shallow, +} + /// Reflects [`rustc_ast::ast::StrStyle`] #[derive(AdtInto)] #[args(, from: rustc_ast::ast::StrStyle, state: S as gstate)] -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum StrStyle { Cooked, Raw(u8), @@ -1975,26 +2270,38 @@ pub enum StrStyle { /// Reflects [`rustc_ast::ast::LitKind`] #[derive(AdtInto)] #[args(<'tcx, S: BaseState<'tcx>>, from: rustc_ast::ast::LitKind, state: S as gstate)] -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum LitKind { Str(Symbol, StrStyle), ByteStr(Vec, StrStyle), CStr(Vec, StrStyle), Byte(u8), Char(char), - Int(u128, LitIntType), + Int( + #[serde(with = "serialize_int::unsigned")] + #[schemars(with = "String")] + u128, + LitIntType, + ), Float(Symbol, LitFloatType), Bool(bool), - Err, + Err(ErrorGuaranteed), +} + +#[cfg(feature = "rustc")] +impl SInto for rustc_data_structures::packed::Pu128 { + fn sinto(&self, _s: &S) -> u128 { + self.0 + } } // FIXME: typo: invo**C**ation #[allow(rustdoc::private_intra_doc_links)] /// Describe a macro invocation, using /// [`macro_invocation_of_raw_mac_invocation`] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub struct MacroInvokation { pub macro_ident: DefId, pub argument: String, @@ -2004,21 +2311,21 @@ pub struct MacroInvokation { /// Reflects [`rustc_hir::ImplicitSelfKind`] #[derive(AdtInto)] #[args(, from: rustc_hir::ImplicitSelfKind, state: S as _s)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub enum ImplicitSelfKind { Imm, Mut, - ImmRef, - MutRef, + RefImm, + RefMut, None, } /// Reflects [`rustc_ast::token::CommentKind`] #[derive(AdtInto)] #[args(, from: rustc_ast::token::CommentKind, state: S as _s)] -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum CommentKind { Line, Block, @@ -2027,9 +2334,8 @@ pub enum CommentKind { /// Reflects [`rustc_ast::ast::AttrArgs`] #[derive(AdtInto)] #[args(<'tcx, S: BaseState<'tcx>>, from: rustc_ast::ast::AttrArgs, state: S as tcx)] -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum AttrArgs { Empty, Delimited(DelimArgs), @@ -2042,9 +2348,8 @@ pub enum AttrArgs { /// Reflects [`rustc_ast::ast::AttrArgsEq`] #[derive(AdtInto)] #[args(<'tcx, S: BaseState<'tcx>>, from: rustc_ast::ast::AttrArgsEq, state: S as tcx)] -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum AttrArgsEq { Hir(MetaItemLit), #[todo] @@ -2055,9 +2360,8 @@ pub enum AttrArgsEq { /// Reflects [`rustc_ast::ast::MetaItemLit`] #[derive(AdtInto)] #[args(<'tcx, S: BaseState<'tcx>>, from: rustc_ast::ast::MetaItemLit, state: S as tcx)] -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct MetaItemLit { pub symbol: Symbol, pub suffix: Option, @@ -2068,9 +2372,8 @@ pub struct MetaItemLit { /// Reflects [`rustc_ast::ast::AttrItem`] #[derive(AdtInto)] #[args(<'tcx, S: BaseState<'tcx>>, from: rustc_ast::ast::AttrItem, state: S as tcx)] -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct AttrItem { #[map(rustc_ast_pretty::pprust::path_to_string(x))] pub path: String, @@ -2078,18 +2381,19 @@ pub struct AttrItem { pub tokens: Option, } +#[cfg(feature = "rustc")] impl SInto for rustc_ast::tokenstream::LazyAttrTokenStream { fn sinto(&self, st: &S) -> String { - self.to_attr_token_stream().to_tokenstream().sinto(st) + rustc_ast::tokenstream::TokenStream::new(self.to_attr_token_stream().to_token_trees()) + .sinto(st) } } /// Reflects [`rustc_ast::ast::NormalAttr`] #[derive(AdtInto)] #[args(<'tcx, S: BaseState<'tcx>>, from: rustc_ast::ast::NormalAttr, state: S as tcx)] -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct NormalAttr { pub item: AttrItem, pub tokens: Option, @@ -2098,9 +2402,8 @@ pub struct NormalAttr { /// Reflects [`rustc_ast::AttrKind`] #[derive(AdtInto)] #[args(<'tcx, S: BaseState<'tcx>>, from: rustc_ast::AttrKind, state: S as tcx)] -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum AttrKind { Normal(NormalAttr), DocComment(CommentKind, Symbol), @@ -2109,7 +2412,8 @@ pub enum AttrKind { /// Reflects [`rustc_middle::thir::Param`] #[derive(AdtInto)] #[args(<'tcx, S: ExprState<'tcx>>, from: rustc_middle::thir::Param<'tcx>, state: S as s)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub struct Param { pub pat: Option, pub ty: Ty, @@ -2126,7 +2430,8 @@ pub struct Param { /// Reflects [`rustc_middle::thir::ExprKind`] #[derive(AdtInto)] #[args(<'tcx, S: ExprState<'tcx>>, from: rustc_middle::thir::ExprKind<'tcx>, state: S as gstate)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] #[append( rustc_middle::thir::ExprKind::Scope {..} => { fatal!(gstate, "Scope should have been eliminated at this point"); @@ -2154,56 +2459,51 @@ pub enum ExprKind { }, #[map({ let e = gstate.thir().exprs[*fun].unroll_scope(gstate); - let (generic_args, r#impl, bounds_impls); - let fun = match &e.kind { - /* TODO: see whether [user_ty] below is relevant or not */ - rustc_middle::thir::ExprKind::ZstLiteral {user_ty: _ } => { - match ty.kind() { - rustc_middle::ty::TyKind::FnDef(def_id, generics) => { - let (hir_id, attributes) = e.hir_id_and_attributes(gstate); - let hir_id = hir_id.map(|hir_id| hir_id.index()); - let contents = Box::new(ExprKind::GlobalName { - id: def_id.sinto(gstate) - }); - let tcx = gstate.base().tcx; - r#impl = tcx.opt_associated_item(*def_id).as_ref().and_then(|assoc| { - poly_trait_ref(gstate, assoc, generics) - }).map(|poly_trait_ref| poly_trait_ref.impl_expr(gstate, gstate.param_env())); - generic_args = generics.sinto(gstate); - bounds_impls = solve_item_traits(gstate, gstate.param_env(), *def_id, generics, None); - Expr { - contents, - span: e.span.sinto(gstate), - ty: e.ty.sinto(gstate), - hir_id, - attributes, - } - }, - ty_kind => supposely_unreachable_fatal!( - gstate[e.span], - "CallNotTyFnDef"; - {e, ty_kind} - ) + let (generic_args, r#trait, bounds_impls); + // A function is any expression whose type is something callable + let fun = match ty.kind() { + rustc_middle::ty::TyKind::FnDef(def_id, generics) => { + let (hir_id, attributes) = e.hir_id_and_attributes(gstate); + let hir_id = hir_id.map(|hir_id| hir_id.index()); + let contents = Box::new(ExprKind::GlobalName { + id: def_id.sinto(gstate) + }); + let mut translated_generics = generics.sinto(gstate); + let tcx = gstate.base().tcx; + r#trait = (|| { + let assoc_item = tcx.opt_associated_item(*def_id)?; + let assoc_trait = tcx.trait_of_item(assoc_item.def_id)?; + let trait_ref = ty::TraitRef::new(tcx, assoc_trait, generics.iter()); + let impl_expr = { + // TODO: we should not wrap into a dummy binder + let poly_trait_ref = ty::Binder::dummy(trait_ref); + poly_trait_ref.impl_expr(gstate, gstate.param_env()) + }; + let assoc_generics = tcx.generics_of(assoc_item.def_id); + let assoc_generics = translated_generics.drain(0..assoc_generics.parent_count); + Some((impl_expr, assoc_generics.collect())) + })(); + generic_args = translated_generics; + bounds_impls = solve_item_traits(gstate, gstate.param_env(), *def_id, generics, None); + Expr { + contents, + span: e.span.sinto(gstate), + ty: e.ty.sinto(gstate), + hir_id, + attributes, } }, - kind => { - match ty.kind() { - rustc_middle::ty::TyKind::FnPtr(..) => { - generic_args = vec![]; // A function pointer has no generics - bounds_impls = vec![]; // A function pointer has no bounds - r#impl = None; // A function pointer is not a method - e.sinto(gstate) - }, - ty_kind => { - supposely_unreachable!( - gstate[e.span], - "CallNotTyFnDef"; - {e, kind, ty_kind} - ); - fatal!(gstate, "RefCallNotTyFnPtr") - } - } - } + rustc_middle::ty::TyKind::FnPtr(..) => { + generic_args = vec![]; // A function pointer has no generics + bounds_impls = vec![]; // A function pointer has no bounds + r#trait = None; // A function pointer is not a method + e.sinto(gstate) + }, + ty_kind => supposely_unreachable_fatal!( + gstate[e.span], + "CallNotTyFnDef"; + {e, ty_kind} + ) }; TO_TYPE::Call { ty: ty.sinto(gstate), @@ -2212,7 +2512,7 @@ pub enum ExprKind { from_hir_call: from_hir_call.sinto(gstate), fn_span: fn_span.sinto(gstate), bounds_impls, - r#impl, + r#trait, fun, } })] @@ -2247,15 +2547,29 @@ pub enum ExprKind { /// one for the implicit `i8: Sized`. #[not_in_source] bounds_impls: Vec, - /// `impl` is `None` if this is a function call or a method to - /// an inherent trait. If this is a method call from a trait - /// `Trait`, then it contains the concrete implementation of - /// `Trait` it is called on. + /// `trait` is `None` if this is a function call or a method + /// to an inherent trait. If this is a method call from a + /// trait `Trait`, then it contains the concrete + /// implementation of `Trait` it is called on, and the generic + /// arguments that comes from the trait declaration. /// /// Example: `f(0i8)` is a function call, hence the field /// `impl` is `None`. + /// + /// Example: + /// ```ignore + /// trait MyTrait { + /// fn meth(...) {...} + /// } + /// fn example_call>(x: SelfType) { + /// x.meth::(...) + /// } + /// ``` + /// Here, in the call `x.meth::(...)`, `r#trait` will + /// be `Some((..., [SelfType, TraitType, 12]))`, and `generic_args` + /// will be `[String]`. #[not_in_source] - r#impl: Option, + r#trait: Option<(ImplExpr, Vec)>, }, Deref { arg: Expr, @@ -2442,6 +2756,7 @@ pub enum ExprKind { Todo(String), } +#[cfg(feature = "rustc")] pub trait ExprKindExt<'tcx> { fn hir_id_and_attributes>( &self, @@ -2453,6 +2768,7 @@ pub trait ExprKindExt<'tcx> { ) -> rustc_middle::thir::Expr<'tcx>; } +#[cfg(feature = "rustc")] impl<'tcx> ExprKindExt<'tcx> for rustc_middle::thir::Expr<'tcx> { fn hir_id_and_attributes>( &self, @@ -2482,9 +2798,8 @@ impl<'tcx> ExprKindExt<'tcx> for rustc_middle::thir::Expr<'tcx> { } /// Reflects [`rustc_middle::ty::FnSig`] -#[derive( - AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::FnSig<'tcx>, state: S as s)] pub struct TyFnSig { #[value(self.inputs().sinto(s))] @@ -2492,7 +2807,7 @@ pub struct TyFnSig { #[value(self.output().sinto(s))] pub output: Ty, pub c_variadic: bool, - pub unsafety: Unsafety, + pub safety: Safety, pub abi: Abi, } @@ -2500,7 +2815,8 @@ pub struct TyFnSig { pub type PolyFnSig = Binder; /// Function definition -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub struct FnDef { pub header: FnHeader, pub params: Vec, @@ -2510,7 +2826,8 @@ pub struct FnDef { } /// Reflects [`rustc_hir::FnDecl`] -#[derive(AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] #[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::FnDecl<'tcx>, state: S as tcx)] pub struct FnDecl { pub inputs: Vec, @@ -2521,7 +2838,8 @@ pub struct FnDecl { } /// Reflects [`rustc_hir::FnSig`] -#[derive(AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] #[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::FnSig<'tcx>, state: S as tcx)] pub struct FnSig { pub header: FnHeader, @@ -2530,10 +2848,11 @@ pub struct FnSig { } /// Reflects [`rustc_hir::FnHeader`] -#[derive(AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema)] -#[args(, from: rustc_hir::FnHeader, state: S as tcx)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::FnHeader, state: S as tcx)] pub struct FnHeader { - pub unsafety: Unsafety, + pub safety: Safety, pub constness: Constness, pub asyncness: IsAsync, pub abi: Abi, @@ -2541,7 +2860,8 @@ pub struct FnHeader { pub type ThirBody = Expr; -impl<'x, 'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_hir::Ty<'x> { +#[cfg(feature = "rustc")] +impl<'x: 'tcx, 'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_hir::Ty<'x> { fn sinto(self: &rustc_hir::Ty<'x>, s: &S) -> Ty { // **Important:** // We need a local id here, and we get it from the owner id, which must @@ -2550,14 +2870,15 @@ impl<'x, 'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_hir::Ty<'x> { // access to the HIR of external objects, only their MIR). let ctx = rustc_hir_analysis::collect::ItemCtxt::new(s.base().tcx, s.owner_id().expect_local()); - ctx.to_ty(self).sinto(s) + ctx.lower_ty(self).sinto(s) } } /// Reflects [`rustc_hir::UseKind`] #[derive(AdtInto)] #[args(, from: rustc_hir::UseKind, state: S as _s)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub enum UseKind { Single, Glob, @@ -2567,7 +2888,8 @@ pub enum UseKind { /// Reflects [`rustc_hir::IsAuto`] #[derive(AdtInto)] #[args(, from: rustc_hir::IsAuto, state: S as _s)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub enum IsAuto { Yes, No, @@ -2576,7 +2898,8 @@ pub enum IsAuto { /// Reflects [`rustc_hir::Defaultness`] #[derive(AdtInto)] #[args(, from: rustc_hir::Defaultness, state: S as tcx)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub enum Defaultness { Default { has_value: bool }, Final, @@ -2585,7 +2908,8 @@ pub enum Defaultness { /// Reflects [`rustc_hir::ImplPolarity`] #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::ImplPolarity, state: S as tcx)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub enum ImplPolarity { Positive, Negative(Span), @@ -2594,7 +2918,8 @@ pub enum ImplPolarity { /// Reflects [`rustc_hir::Constness`] #[derive(AdtInto)] #[args(, from: rustc_hir::Constness, state: S as _s)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub enum Constness { Const, NotConst, @@ -2603,7 +2928,8 @@ pub enum Constness { /// Reflects [`rustc_hir::Generics`] #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::Generics<'tcx>, state: S as tcx)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub struct Generics { pub params: Vec>, pub predicates: Vec>, @@ -2617,13 +2943,15 @@ pub struct Generics { /// Reflects [`rustc_hir::WherePredicate`] #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::WherePredicate<'tcx>, state: S as tcx)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub enum WherePredicate { BoundPredicate(WhereBoundPredicate), RegionPredicate(WhereRegionPredicate), EqPredicate(WhereEqPredicate), } +#[cfg(feature = "rustc")] impl<'tcx, S: UnderOwnerState<'tcx>, Body: IsBody> SInto> for rustc_hir::ImplItemRef { @@ -2636,7 +2964,8 @@ impl<'tcx, S: UnderOwnerState<'tcx>, Body: IsBody> SInto> } /// Reflects [`rustc_hir::ParamName`] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub enum ParamName { Plain(LocalIdent), Fresh, @@ -2646,15 +2975,17 @@ pub enum ParamName { /// Reflects [`rustc_hir::LifetimeParamKind`] #[derive(AdtInto)] #[args(, from: rustc_hir::LifetimeParamKind, state: S as _s)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub enum LifetimeParamKind { Explicit, - Elided, + Elided(MissingLifetimeKind), Error, } /// Reflects [`rustc_hir::AnonConst`] -#[derive(AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::AnonConst, state: S as s)] pub struct AnonConst { pub hir_id: HirId, @@ -2665,8 +2996,28 @@ pub struct AnonConst { pub body: Body, } +/// Reflects [`rustc_hir::ConstArg`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::ConstArg<'tcx>, state: S as s)] +pub struct ConstArg { + pub hir_id: HirId, + pub kind: ConstArgKind, + pub is_desugared_from_effects: bool, +} + +/// Reflects [`rustc_hir::ConstArgKind`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::ConstArgKind<'tcx>, state: S as s)] +pub enum ConstArgKind { + Path(QPath), + Anon(AnonConst), +} + /// Reflects [`rustc_hir::GenericParamKind`] -#[derive(AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] #[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::GenericParamKind<'tcx>, state: S as tcx)] pub enum GenericParamKind { Lifetime { @@ -2679,12 +3030,13 @@ pub enum GenericParamKind { }, Const { ty: Ty, - default: Option>, + default: Option>, }, } /// Reflects [`rustc_hir::GenericParam`] -#[derive(AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] #[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::GenericParam<'tcx>, state: S as s)] pub struct GenericParam { pub hir_id: HirId, @@ -2710,7 +3062,8 @@ pub struct GenericParam { } /// Reflects [`rustc_hir::ImplItem`] -#[derive(AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] #[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::ImplItem<'tcx>, state: S as s)] pub struct ImplItem { pub ident: Ident, @@ -2728,7 +3081,8 @@ pub struct ImplItem { /// Reflects [`rustc_hir::ImplItemKind`], inlining the body of the items. #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::ImplItemKind<'tcx>, state: S as s)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub enum ImplItemKind { Const(Ty, Body), #[custom_arm(rustc_hir::ImplItemKind::Fn(sig, body) => { @@ -2762,19 +3116,21 @@ pub enum ImplItemKind { /// Reflects [`rustc_hir::AssocItemKind`] #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::AssocItemKind, state: S as tcx)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub enum AssocItemKind { Const, Fn { has_self: bool }, Type, } +#[cfg(feature = "rustc")] impl< 'tcx, S, D: Clone, T: SInto + rustc_middle::ty::TypeFoldable>, - > SInto for rustc_middle::ty::EarlyBinder + > SInto for rustc_middle::ty::EarlyBinder<'tcx, T> { fn sinto(&self, s: &S) -> D { self.clone().instantiate_identity().sinto(s) @@ -2784,9 +3140,10 @@ impl< /// Reflects [`rustc_hir::Impl`]. #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::Impl<'tcx>, state: S as s)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub struct Impl { - pub unsafety: Unsafety, + pub safety: Safety, pub polarity: ImplPolarity, pub defaultness: Defaultness, pub defaultness_span: Option, @@ -2801,7 +3158,7 @@ pub struct Impl { let (tcx, owner_id) = (s.base().tcx, s.owner_id()); let trait_did = tcx.trait_id_of_impl(owner_id); if let Some(trait_did) = trait_did { - tcx.super_predicates_of(trait_did) + tcx.explicit_super_predicates_of(trait_did) .predicates .iter() .copied() @@ -2818,35 +3175,52 @@ pub struct Impl { /// Reflects [`rustc_hir::IsAsync`] #[derive(AdtInto)] -#[args(, from: rustc_hir::IsAsync, state: S as _s)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::IsAsync, state: S as _s)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub enum IsAsync { - Async, + Async(Span), NotAsync, } /// Reflects [`rustc_hir::FnRetTy`] #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::FnRetTy<'tcx>, state: S as tcx)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub enum FnRetTy { DefaultReturn(Span), Return(Ty), } /// Reflects [`rustc_hir::VariantData`] -#[derive(AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] #[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::VariantData<'tcx>, state: S as tcx)] pub enum VariantData { - Struct(Vec, bool), + Struct { + fields: Vec, + recovered: bool, + }, Tuple(Vec, HirId, GlobalIdent), Unit(HirId, GlobalIdent), } +#[cfg(feature = "rustc")] +impl SInto for rustc_ast::ast::Recovered { + fn sinto(&self, _s: &S) -> bool { + match self { + Self::Yes(_) => true, + Self::No => false, + } + } +} + /// Reflects [`rustc_hir::FieldDef`] #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::FieldDef<'tcx>, state: S as s)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub struct HirFieldDef { pub span: Span, pub vis_span: Span, @@ -2861,7 +3235,8 @@ pub struct HirFieldDef { /// Reflects [`rustc_hir::Variant`] #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::Variant<'tcx>, state: S as s)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub struct Variant { pub ident: Ident, pub hir_id: HirId, @@ -2878,7 +3253,7 @@ pub struct Variant { .find(|v| v.def_id == self.def_id.into()).unwrap(); variant.discr.sinto(s) })] - pub discr: VariantDiscr, + pub discr: DiscriminantDefinition, pub span: Span, #[value(s.base().tcx.hir().attrs(hir_id.clone()).sinto(s))] pub attributes: Vec, @@ -2887,19 +3262,20 @@ pub struct Variant { /// Reflects [`rustc_hir::UsePath`] #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::UsePath<'tcx>, state: S as s)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub struct UsePath { pub span: Span, #[map(x.iter().map(|res| res.sinto(s)).collect())] pub res: Vec, pub segments: Vec, #[value(self.segments.iter().last().map_or(None, |segment| { - match s.base().tcx.hir().find_by_def_id(segment.hir_id.owner.def_id) { - Some(rustc_hir::Node::Item(rustc_hir::Item { + match s.base().tcx.hir_node_by_def_id(segment.hir_id.owner.def_id) { + rustc_hir::Node::Item(rustc_hir::Item { ident, kind: rustc_hir::ItemKind::Use(_, _), .. - })) if ident.name.to_ident_string() != "" => Some(ident.name.to_ident_string()), + }) if ident.name.to_ident_string() != "" => Some(ident.name.to_ident_string()), _ => None, } }))] @@ -2909,7 +3285,8 @@ pub struct UsePath { /// Reflects [`rustc_hir::def::Res`] #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::def::Res, state: S as s)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub enum Res { Def(DefKind, DefId), PrimTy(PrimTy), @@ -2931,7 +3308,8 @@ pub enum Res { /// Reflects [`rustc_hir::PrimTy`] #[derive(AdtInto)] #[args(, from: rustc_hir::PrimTy, state: S as s)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub enum PrimTy { Int(IntTy), Uint(UintTy), @@ -2944,7 +3322,8 @@ pub enum PrimTy { /// Reflects [`rustc_hir::def::NonMacroAttrKind`] #[derive(AdtInto)] #[args(, from: rustc_hir::def::NonMacroAttrKind, state: S as s)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub enum NonMacroAttrKind { Builtin(Symbol), Tool, @@ -2955,7 +3334,8 @@ pub enum NonMacroAttrKind { /// Reflects [`rustc_hir::PathSegment`] #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::PathSegment<'tcx>, state: S as s)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub struct PathSegment { pub ident: Ident, pub hir_id: HirId, @@ -2968,7 +3348,8 @@ pub struct PathSegment { /// Reflects [`rustc_hir::ItemKind`] #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::ItemKind<'tcx>, state: S as s)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub enum ItemKind { #[disable_mapping] MacroInvokation(MacroInvokation), @@ -2989,14 +3370,26 @@ pub enum ItemKind { items: Vec>, }, GlobalAsm(InlineAsm), - TyAlias(Ty, Generics), + TyAlias( + #[map({ + let s = &State { + thir: s.clone(), + owner_id: s.owner_id(), + base: Base {ty_alias_mode: true, ..s.base()}, + mir: (), + }; + x.sinto(s) + })] + Ty, + Generics, + ), OpaqueTy(OpaqueTy), Enum( EnumDef, Generics, #[value({ let tcx = s.base().tcx; - tcx.repr_options_of_def(s.owner_id()).sinto(s) + tcx.repr_options_of_def(s.owner_id().expect_local()).sinto(s) })] ReprOptions, ), @@ -3004,7 +3397,7 @@ pub enum ItemKind { Union(VariantData, Generics), Trait( IsAuto, - Unsafety, + Safety, Generics, GenericBounds, Vec>, @@ -3018,7 +3411,8 @@ pub type EnumDef = Vec>; /// Reflects [`rustc_hir::TraitItemKind`] #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::TraitItemKind<'tcx>, state: S as tcx)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive(Clone, Debug, JsonSchema)] +#[derive_group(Serializers)] pub enum TraitItemKind { Const(Ty, Option), #[custom_arm( @@ -3046,7 +3440,8 @@ pub enum TraitItemKind { /// Reflects [`rustc_hir::TraitItem`] #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::TraitItem<'tcx>, state: S as s)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub struct TraitItem { pub ident: Ident, pub owner_id: DefId, @@ -3059,6 +3454,7 @@ pub struct TraitItem { pub attributes: ItemAttributes, } +#[cfg(feature = "rustc")] impl<'tcx, S: UnderOwnerState<'tcx>, Body: IsBody> SInto> for rustc_hir::EnumDef<'tcx> { @@ -3067,6 +3463,7 @@ impl<'tcx, S: UnderOwnerState<'tcx>, Body: IsBody> SInto> } } +#[cfg(feature = "rustc")] impl<'a, S: UnderOwnerState<'a>, Body: IsBody> SInto> for rustc_hir::TraitItemRef { @@ -3077,6 +3474,7 @@ impl<'a, S: UnderOwnerState<'a>, Body: IsBody> SInto> } } +#[cfg(feature = "rustc")] impl<'a, 'tcx, S: UnderOwnerState<'tcx>, Body: IsBody> SInto>> for rustc_hir::Mod<'a> { @@ -3091,17 +3489,19 @@ impl<'a, 'tcx, S: UnderOwnerState<'tcx>, Body: IsBody> SInto>> /// Reflects [`rustc_hir::ForeignItemKind`] #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::ForeignItemKind<'tcx>, state: S as tcx)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive(Clone, Debug, JsonSchema)] +#[derive_group(Serializers)] pub enum ForeignItemKind { - Fn(FnDecl, Vec, Generics), - Static(Ty, Mutability), + Fn(FnDecl, Vec, Generics, Safety), + Static(Ty, Mutability, Safety), Type, } /// Reflects [`rustc_hir::ForeignItem`] #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::ForeignItem<'tcx>, state: S as tcx)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub struct ForeignItem { pub ident: Ident, pub kind: ForeignItemKind, @@ -3110,6 +3510,7 @@ pub struct ForeignItem { pub vis_span: Span, } +#[cfg(feature = "rustc")] impl<'a, S: UnderOwnerState<'a>, Body: IsBody> SInto> for rustc_hir::ForeignItemRef { @@ -3122,7 +3523,8 @@ impl<'a, S: UnderOwnerState<'a>, Body: IsBody> SInto> /// Reflects [`rustc_hir::OpaqueTy`] #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::OpaqueTy<'tcx>, state: S as tcx)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub struct OpaqueTy { pub generics: Generics, pub bounds: GenericBounds, @@ -3133,7 +3535,8 @@ pub struct OpaqueTy { /// Reflects [`rustc_hir::LifetimeName`] #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::LifetimeName, state: S as tcx)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive(Clone, Debug, JsonSchema)] +#[derive_group(Serializers)] pub enum LifetimeName { Param(GlobalIdent), ImplicitObjectLifetimeDefault, @@ -3145,7 +3548,8 @@ pub enum LifetimeName { /// Reflects [`rustc_hir::Lifetime`] #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::Lifetime, state: S as tcx)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub struct Lifetime { pub hir_id: HirId, pub ident: Ident, @@ -3153,11 +3557,10 @@ pub struct Lifetime { } /// Reflects [`rustc_middle::ty::TraitRef`] +#[derive_group(Serializers)] #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::TraitRef<'tcx>, state: S as tcx)] -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct TraitRef { pub def_id: DefId, #[from(args)] @@ -3168,12 +3571,11 @@ pub struct TraitRef { /// Reflects [`rustc_middle::ty::TraitPredicate`] #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::TraitPredicate<'tcx>, state: S as tcx)] -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct TraitPredicate { pub trait_ref: TraitRef, - #[map(x.clone() == rustc_middle::ty::ImplPolarity::Positive)] + #[map(x.clone() == rustc_middle::ty::PredicatePolarity::Positive)] #[from(polarity)] pub is_positive: bool, } @@ -3182,21 +3584,20 @@ pub struct TraitPredicate { /// instead of a tuple struct. This is because the script converting /// JSONSchema types to OCaml doesn't support tuple structs, and this /// is the only tuple struct in the whole AST. -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] -pub struct OutlivesPredicate { - pub lhs: A, - pub rhs: B, +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct OutlivesPredicate { + pub lhs: T, + pub rhs: Region, } -impl<'tcx, S: UnderOwnerState<'tcx>, A1, A2, B1, B2> SInto> - for rustc_middle::ty::OutlivesPredicate +#[cfg(feature = "rustc")] +impl<'tcx, S: UnderOwnerState<'tcx>, T, U> SInto> + for rustc_middle::ty::OutlivesPredicate<'tcx, T> where - A1: SInto, - B1: SInto, + T: SInto, { - fn sinto(&self, s: &S) -> OutlivesPredicate where { + fn sinto(&self, s: &S) -> OutlivesPredicate where { OutlivesPredicate { lhs: self.0.sinto(s), rhs: self.1.sinto(s), @@ -3205,19 +3606,19 @@ where } /// Reflects [`rustc_middle::ty::RegionOutlivesPredicate`] -pub type RegionOutlivesPredicate = OutlivesPredicate; +pub type RegionOutlivesPredicate = OutlivesPredicate; /// Reflects [`rustc_middle::ty::TypeOutlivesPredicate`] -pub type TypeOutlivesPredicate = OutlivesPredicate; +pub type TypeOutlivesPredicate = OutlivesPredicate; /// Reflects [`rustc_middle::ty::Term`] -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum Term { Ty(Ty), Const(ConstantExpr), } +#[cfg(feature = "rustc")] impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::Term<'tcx> { fn sinto(&self, s: &S) -> Term { use rustc_middle::ty::TermKind; @@ -3236,9 +3637,8 @@ impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::Term<' /// ^^^^^^^^^^ /// ``` /// (provided the trait `Foo` has an associated type `S`). -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct ProjectionPredicate { /// The `impl Trait for Ty` in `Ty: Trait<..., Type = U>`. pub impl_expr: ImplExpr, @@ -3248,17 +3648,19 @@ pub struct ProjectionPredicate { pub ty: Ty, } +#[cfg(feature = "rustc")] impl<'tcx, S: BaseState<'tcx> + HasOwnerId> SInto for rustc_middle::ty::ProjectionPredicate<'tcx> { fn sinto(&self, s: &S) -> ProjectionPredicate { + let tcx = s.base().tcx; let AliasKind::Projection { impl_expr, assoc_item, } = Alias::from( s, - &rustc_middle::ty::AliasKind::Projection, - &self.projection_ty, + &rustc_middle::ty::AliasTyKind::Projection, + &self.projection_term.expect_ty(tcx), ) .kind else { @@ -3278,9 +3680,8 @@ impl<'tcx, S: BaseState<'tcx> + HasOwnerId> SInto /// Reflects [`rustc_middle::ty::ClauseKind`] #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::ClauseKind<'tcx>, state: S as tcx)] -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum ClauseKind { Trait(TraitPredicate), RegionOutlives(RegionOutlivesPredicate), @@ -3292,14 +3693,14 @@ pub enum ClauseKind { } /// Reflects [`rustc_middle::ty::Clause`] and adds a hash-consed predicate identifier. -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Clause { pub kind: Binder, pub id: PredicateId, } +#[cfg(feature = "rustc")] impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::Clause<'tcx> { fn sinto(&self, s: &S) -> Clause { Clause { @@ -3310,14 +3711,14 @@ impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::Clau } /// Reflects [`rustc_middle::ty::Predicate`] and adds a hash-consed predicate identifier. -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Predicate { pub kind: Binder, pub id: PredicateId, } +#[cfg(feature = "rustc")] impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::Predicate<'tcx> { fn sinto(&self, s: &S) -> Predicate { Predicate { @@ -3330,9 +3731,8 @@ impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::P /// Reflects [`rustc_middle::ty::BoundVariableKind`] #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::BoundVariableKind, state: S as tcx)] -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum BoundVariableKind { Ty(BoundTyKind), Region(BoundRegionKind), @@ -3340,9 +3740,8 @@ pub enum BoundVariableKind { } /// Reflects [`rustc_middle::ty::Binder`] -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Binder { pub value: T, pub bound_vars: Vec, @@ -3351,9 +3750,8 @@ pub struct Binder { /// Reflects [`rustc_middle::ty::GenericPredicates`] #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::GenericPredicates<'tcx>, state: S as s)] -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct GenericPredicates { pub parent: Option, // FIXME: Switch from `Predicate` to `Clause` (will require correct handling of binders). @@ -3361,6 +3759,7 @@ pub struct GenericPredicates { pub predicates: Vec<(Predicate, Span)>, } +#[cfg(feature = "rustc")] impl<'tcx, S: UnderOwnerState<'tcx>, T1, T2> SInto> for rustc_middle::ty::Binder<'tcx, T1> where @@ -3376,9 +3775,8 @@ where /// Reflects [`rustc_middle::ty::SubtypePredicate`] #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::SubtypePredicate<'tcx>, state: S as tcx)] -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct SubtypePredicate { pub a_is_expected: bool, pub a: Ty, @@ -3388,9 +3786,8 @@ pub struct SubtypePredicate { /// Reflects [`rustc_middle::ty::CoercePredicate`] #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::CoercePredicate<'tcx>, state: S as tcx)] -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct CoercePredicate { pub a: Ty, pub b: Ty, @@ -3399,20 +3796,34 @@ pub struct CoercePredicate { /// Reflects [`rustc_middle::ty::AliasRelationDirection`] #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::AliasRelationDirection, state: S as _tcx)] -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum AliasRelationDirection { Equate, Subtype, } +/// Reflects [`rustc_middle::ty::ClosureArgs`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: ty::ClosureArgs>, state: S as s)] +#[derive(Clone, Debug, JsonSchema)] +#[derive_group(Serializers)] +pub struct ClosureArgs { + #[value(self.kind().sinto(s))] + pub kind: ClosureKind, + #[value(self.parent_args().sinto(s))] + pub parent_args: Vec, + #[value(self.sig().sinto(s))] + pub sig: PolyFnSig, + #[value(self.upvar_tys().sinto(s))] + pub upvar_tys: Vec, +} + /// Reflects [`rustc_middle::ty::ClosureKind`] #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::ClosureKind, state: S as _tcx)] -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum ClosureKind { Fn, FnMut, @@ -3422,24 +3833,44 @@ pub enum ClosureKind { /// Reflects [`rustc_middle::ty::PredicateKind`] #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::PredicateKind<'tcx>, state: S as tcx)] -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum PredicateKind { Clause(ClauseKind), ObjectSafe(DefId), - ClosureKind(DefId, Vec, ClosureKind), Subtype(SubtypePredicate), Coerce(CoercePredicate), ConstEquate(ConstantExpr, ConstantExpr), Ambiguous, AliasRelate(Term, Term, AliasRelationDirection), + NormalizesTo(NormalizesTo), +} + +/// Reflects [`rustc_middle::ty::ImplSubject`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::ImplSubject<'tcx>, state: S as s)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub enum ImplSubject { + Trait( + // Also record the polarity. + #[map({ + let polarity = s.base().tcx.impl_polarity(s.owner_id()); + TraitPredicate { + trait_ref: x.sinto(s), + is_positive: matches!(polarity, rustc_middle::ty::ImplPolarity::Positive), + } + })] + TraitPredicate, + ), + Inherent(Ty), } /// Reflects [`rustc_hir::GenericBounds`] type GenericBounds = Vec; /// Compute the bounds for the owner registed in the state `s` +#[cfg(feature = "rustc")] fn region_bounds_at_current_owner<'tcx, S: UnderOwnerState<'tcx>>(s: &S) -> GenericBounds { let tcx = s.base().tcx; @@ -3447,8 +3878,8 @@ fn region_bounds_at_current_owner<'tcx, S: UnderOwnerState<'tcx>>(s: &S) -> Gene // either call `predicates_defined_on` or `item_bounds` let use_item_bounds = { if let Some(oid) = s.owner_id().as_local() { - let hir_id = tcx.hir().local_def_id_to_hir_id(oid); - let node = tcx.hir().get(hir_id); + let hir_id = tcx.local_def_id_to_hir_id(oid); + let node = tcx.hir_node(hir_id); use rustc_hir as hir; matches!( node, @@ -3481,6 +3912,7 @@ fn region_bounds_at_current_owner<'tcx, S: UnderOwnerState<'tcx>>(s: &S) -> Gene clauses.sinto(s) } +#[cfg(feature = "rustc")] impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_hir::GenericBounds<'tcx> { fn sinto(&self, s: &S) -> GenericBounds { region_bounds_at_current_owner(s) @@ -3490,7 +3922,8 @@ impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_hir::Gene /// Reflects [`rustc_hir::OpaqueTyOrigin`] #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::OpaqueTyOrigin, state: S as tcx)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive(Clone, Debug, JsonSchema)] +#[derive_group(Serializers)] pub enum OpaqueTyOrigin { FnReturn(GlobalIdent), AsyncFn(GlobalIdent), @@ -3500,14 +3933,16 @@ pub enum OpaqueTyOrigin { /// Reflects [`rustc_ast::ast::MacroDef`] #[derive(AdtInto)] #[args(<'tcx, S: BaseState<'tcx>>, from: rustc_ast::ast::MacroDef, state: S as tcx)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub struct MacroDef { pub body: DelimArgs, pub macro_rules: bool, } /// Reflects [`rustc_hir::Item`] (and [`rustc_hir::ItemId`]) -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub struct Item { pub def_id: Option, pub owner_id: DefId, @@ -3518,6 +3953,7 @@ pub struct Item { pub expn_backtrace: Vec, } +#[cfg(feature = "rustc")] impl<'tcx, S: BaseState<'tcx>, Body: IsBody> SInto> for rustc_hir::Item<'tcx> { fn sinto(&self, s: &S) -> Item { let name: String = self.ident.name.to_ident_string(); @@ -3538,6 +3974,7 @@ impl<'tcx, S: BaseState<'tcx>, Body: IsBody> SInto> for rustc_hir: } } +#[cfg(feature = "rustc")] impl<'tcx, S: BaseState<'tcx>, Body: IsBody> SInto> for rustc_hir::ItemId { fn sinto(&self, s: &S) -> Item { let tcx: rustc_middle::ty::TyCtxt = s.base().tcx; @@ -3548,6 +3985,7 @@ impl<'tcx, S: BaseState<'tcx>, Body: IsBody> SInto> for rustc_hir: /// Reflects [`rustc_span::symbol::Ident`] pub type Ident = (Symbol, Span); +#[cfg(feature = "rustc")] impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_span::symbol::Ident { fn sinto(&self, s: &S) -> Ident { (self.name.sinto(s), self.span.sinto(s)) @@ -3557,7 +3995,8 @@ impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_span::symbol::Ide /// Reflects [`rustc_hir::WhereBoundPredicate`] #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::WhereBoundPredicate<'tcx>, state: S as tcx)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub struct WhereBoundPredicate { pub hir_id: HirId, pub span: Span, @@ -3571,7 +4010,8 @@ pub struct WhereBoundPredicate { /// Reflects [`rustc_hir::PredicateOrigin`] #[derive(AdtInto)] #[args(, from: rustc_hir::PredicateOrigin, state: S as _s)] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub enum PredicateOrigin { WhereClause, GenericParam, @@ -3580,26 +4020,28 @@ pub enum PredicateOrigin { /// Reflects [`rustc_middle::ty::AssocItem`] #[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::AssocItem, state: S as tcx)] -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[args(<'tcx, S: BaseState<'tcx>>, from: rustc_middle::ty::AssocItem, state: S as s)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct AssocItem { pub def_id: DefId, pub name: Symbol, pub kind: AssocKind, + #[value(get_container_for_assoc_item(s, self))] pub container: AssocItemContainer, - pub trait_item_def_id: Option, + /// Whether this item has a value (e.g. this is `false` for trait methods without default + /// implementations). + #[value(self.defaultness(s.base().tcx).has_value())] + pub has_value: bool, pub fn_has_self_parameter: bool, pub opt_rpitit_info: Option, } /// Reflects [`rustc_middle::ty::ImplTraitInTraitData`] #[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::ImplTraitInTraitData, state: S as _tcx)] -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[args(<'tcx, S: BaseState<'tcx>>, from: rustc_middle::ty::ImplTraitInTraitData, state: S as _s)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum ImplTraitInTraitData { Trait { fn_def_id: DefId, @@ -3610,23 +4052,62 @@ pub enum ImplTraitInTraitData { }, } -/// Reflects [`rustc_middle::ty::AssocItemContainer`] -#[derive(AdtInto)] -#[args(, from: rustc_middle::ty::AssocItemContainer, state: S as _tcx)] -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum AssocItemContainer { - TraitContainer, - ImplContainer, + TraitContainer { + trait_id: DefId, + }, + TraitImplContainer { + impl_id: DefId, + implemented_trait: DefId, + implemented_trait_item: DefId, + /// Whether the corresponding trait item had a default (and therefore this one overrides + /// it). + overrides_default: bool, + }, + InherentImplContainer { + impl_id: DefId, + }, +} + +#[cfg(feature = "rustc")] +fn get_container_for_assoc_item<'tcx, S: BaseState<'tcx>>( + s: &S, + item: &ty::AssocItem, +) -> AssocItemContainer { + let container_id = item.container_id(s.base().tcx); + match item.container { + ty::AssocItemContainer::TraitContainer => AssocItemContainer::TraitContainer { + trait_id: container_id.sinto(s), + }, + ty::AssocItemContainer::ImplContainer => { + if let Some(implemented_trait_item) = item.trait_item_def_id { + AssocItemContainer::TraitImplContainer { + impl_id: container_id.sinto(s), + implemented_trait: s + .base() + .tcx + .trait_of_item(implemented_trait_item) + .unwrap() + .sinto(s), + implemented_trait_item: implemented_trait_item.sinto(s), + overrides_default: s.base().tcx.defaultness(implemented_trait_item).has_value(), + } + } else { + AssocItemContainer::InherentImplContainer { + impl_id: container_id.sinto(s), + } + } + } + } } /// Reflects [`rustc_middle::ty::AssocKind`] #[derive(AdtInto)] #[args(, from: rustc_middle::ty::AssocKind, state: S as _tcx)] -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum AssocKind { Const, Fn, diff --git a/frontend/exporter/src/types/def_id.rs b/frontend/exporter/src/types/def_id.rs index ef5c7a33c..517ebd8cd 100644 --- a/frontend/exporter/src/types/def_id.rs +++ b/frontend/exporter/src/types/def_id.rs @@ -10,14 +10,18 @@ //! `hax-engine-names-extract`, and is used to turn off the derive //! attributes `AdtInto` and `JsonSchema`. -pub use serde::{Deserialize, Serialize}; +use hax_adt_into::derive_group; #[cfg(not(feature = "extract_names_mode"))] -use crate::{AdtInto, BaseState, JsonSchema, SInto}; +use crate::{AdtInto, JsonSchema}; + +#[cfg(all(not(feature = "extract_names_mode"), feature = "rustc"))] +use crate::{BaseState, SInto}; pub type Symbol = String; -#[derive(Clone, Debug, Serialize, Deserialize, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(not(feature = "extract_names_mode"), derive(AdtInto, JsonSchema))] #[cfg_attr(not(feature = "extract_names_mode"), args(<'a, S: BaseState<'a>>, from: rustc_hir::definitions::DisambiguatedDefPathData, state: S as s))] /// Reflects [`rustc_hir::definitions::DisambiguatedDefPathData`] @@ -27,7 +31,8 @@ pub struct DisambiguatedDefPathItem { } /// Reflects [`rustc_hir::def_id::DefId`] -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)] +#[derive_group(Serializers)] +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(not(feature = "extract_names_mode"), derive(JsonSchema))] pub struct DefId { pub krate: String, @@ -41,10 +46,30 @@ pub struct DefId { /// valid only for one Rustc sesssion. Please do not rely on those /// indexes unless you cannot do otherwise. pub index: (u32, u32), + pub is_local: bool, +} + +#[cfg(not(feature = "rustc"))] +impl std::fmt::Debug for DefId { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("DefId") + .field("krate", &self.krate) + .field("path", &self.path) + .finish() + } +} + +#[cfg(feature = "rustc")] +impl std::fmt::Debug for DefId { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + // Use the more legible rustc debug implementation. + write!(f, "{:?}", rustc_span::def_id::DefId::from(self)) + } } /// Reflects [`rustc_hir::definitions::DefPathData`] -#[derive(Clone, Debug, Serialize, Deserialize, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(not(feature = "extract_names_mode"), derive(AdtInto, JsonSchema))] #[cfg_attr(not(feature = "extract_names_mode"), args(<'ctx, S: BaseState<'ctx>>, from: rustc_hir::definitions::DefPathData, state: S as state))] pub enum DefPathItem { @@ -57,9 +82,9 @@ pub enum DefPathItem { ValueNs(Symbol), MacroNs(Symbol), LifetimeNs(Symbol), - ClosureExpr, + Closure, Ctor, AnonConst, - ImplTrait, - ImplTraitAssocTy, + OpaqueTy, + AnonAdt, } diff --git a/frontend/exporter/src/types/index.rs b/frontend/exporter/src/types/index.rs index 3ce6a3701..2a9c2cc18 100644 --- a/frontend/exporter/src/types/index.rs +++ b/frontend/exporter/src/types/index.rs @@ -1,3 +1,4 @@ +#[cfg(feature = "rustc")] use crate::prelude::*; use crate::sinto_as_usize; diff --git a/frontend/exporter/src/types/mir.rs b/frontend/exporter/src/types/mir.rs index 97c19eaae..0ea0ed120 100644 --- a/frontend/exporter/src/types/mir.rs +++ b/frontend/exporter/src/types/mir.rs @@ -1,7 +1,9 @@ use crate::prelude::*; +#[cfg(feature = "rustc")] use tracing::trace; -#[derive(AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] #[args(, from: rustc_middle::mir::MirPhase, state: S as s)] pub enum MirPhase { Built, @@ -9,19 +11,20 @@ pub enum MirPhase { Runtime(RuntimePhase), } -#[derive(AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::mir::SourceInfo, state: S as s)] pub struct SourceInfo { pub span: Span, pub scope: SourceScope, } -#[derive(AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::mir::LocalDecl<'tcx>, state: S as s)] pub struct LocalDecl { pub mutability: Mutability, pub local_info: ClearCrossCrate, - pub internal: bool, pub ty: Ty, pub user_ty: Option, pub source_info: SourceInfo, @@ -29,12 +32,14 @@ pub struct LocalDecl { pub name: Option, // This information is contextual, thus the SInto instance initializes it to None, and then we fill it while `SInto`ing MirBody } -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub enum ClearCrossCrate { Clear, Set(T), } +#[cfg(feature = "rustc")] impl> SInto> for rustc_middle::mir::ClearCrossCrate { @@ -46,7 +51,8 @@ impl> SInto> } } -#[derive(AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] #[args(, from: rustc_middle::mir::RuntimePhase, state: S as _s)] pub enum RuntimePhase { Initial, @@ -54,7 +60,8 @@ pub enum RuntimePhase { Optimized, } -#[derive(AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] #[args(, from: rustc_middle::mir::AnalysisPhase, state: S as _s)] pub enum AnalysisPhase { Initial, @@ -63,6 +70,7 @@ pub enum AnalysisPhase { pub type BasicBlocks = IndexVec; +#[cfg(feature = "rustc")] fn name_of_local( local: rustc_middle::mir::Local, var_debug_info: &Vec, @@ -82,41 +90,44 @@ fn name_of_local( /// Enumerates the kinds of Mir bodies. TODO: use const generics /// instead of an open list of types. pub mod mir_kinds { - use crate::prelude::{Deserialize, JsonSchema, Serialize}; - use rustc_data_structures::steal::Steal; - use rustc_middle::mir::Body; - use rustc_middle::ty::TyCtxt; - use rustc_span::def_id::LocalDefId; - pub trait IsMirKind: Clone { - fn get_mir<'tcx>(tcx: TyCtxt<'tcx>, id: LocalDefId) -> &'tcx Steal>; - } - #[derive(Clone, Copy, Debug, JsonSchema, Serialize, Deserialize)] - pub struct Const; - impl IsMirKind for Const { - fn get_mir<'tcx>(tcx: TyCtxt<'tcx>, id: LocalDefId) -> &'tcx Steal> { - tcx.mir_const(id) - } - } - #[derive(Clone, Copy, Debug, JsonSchema, Serialize, Deserialize)] + use crate::prelude::{derive_group, JsonSchema}; + #[derive_group(Serializers)] + #[derive(Clone, Copy, Debug, JsonSchema)] pub struct Built; - impl IsMirKind for Built { - fn get_mir<'tcx>(tcx: TyCtxt<'tcx>, id: LocalDefId) -> &'tcx Steal> { - tcx.mir_built(id) + #[cfg(feature = "rustc")] + pub use rustc::*; + #[cfg(feature = "rustc")] + mod rustc { + use super::*; + use rustc_data_structures::steal::Steal; + use rustc_middle::mir::Body; + use rustc_middle::ty::TyCtxt; + use rustc_span::def_id::LocalDefId; + pub trait IsMirKind: Clone { + fn get_mir<'tcx>(tcx: TyCtxt<'tcx>, id: LocalDefId) -> &'tcx Steal>; + } + impl IsMirKind for Built { + fn get_mir<'tcx>(tcx: TyCtxt<'tcx>, id: LocalDefId) -> &'tcx Steal> { + tcx.mir_built(id) + } } } - // TODO: Add [Promoted] MIR } + +#[cfg(feature = "rustc")] pub use mir_kinds::IsMirKind; -#[derive(AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::mir::Constant<'tcx>, state: S as s)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::mir::ConstOperand<'tcx>, state: S as s)] pub struct Constant { pub span: Span, pub user_ty: Option, - pub literal: TypedConstantKind, + pub const_: TypedConstantKind, } -#[derive(AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] #[args(<'tcx, S: UnderOwnerState<'tcx> + HasMir<'tcx>>, from: rustc_middle::mir::Body<'tcx>, state: S as s)] pub struct MirBody { #[map(x.clone().as_mut().sinto(s))] @@ -125,7 +136,7 @@ pub struct MirBody { pub pass_count: usize, pub source: MirSource, pub source_scopes: IndexVec, - pub generator: Option, + pub coroutine: Option, #[map({ let mut local_decls: rustc_index::IndexVec = x.iter().map(|local_decl| { local_decl.sinto(s) @@ -142,7 +153,6 @@ pub struct MirBody { pub spread_arg: Option, pub var_debug_info: Vec, pub span: Span, - pub required_consts: Vec, pub is_polymorphic: bool, pub injection_phase: Option, pub tainted_by_errors: Option, @@ -150,7 +160,8 @@ pub struct MirBody { pub _kind: std::marker::PhantomData, } -#[derive(AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::mir::SourceScopeData<'tcx>, state: S as s)] pub struct SourceScopeData { pub span: Span, @@ -160,30 +171,23 @@ pub struct SourceScopeData { pub local_data: ClearCrossCrate, } -#[derive(AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::Instance<'tcx>, state: S as s)] pub struct Instance { - pub def: InstanceDef, + pub def: InstanceKind, pub args: Vec, } -#[derive(AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::mir::SourceScopeLocalData, state: S as s)] pub struct SourceScopeLocalData { pub lint_root: HirId, - pub safety: Safety, -} - -#[derive(AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::mir::Safety, state: S as s)] -pub enum Safety { - Safe, - BuiltinUnsafe, - FnUnsafe, - ExplicitUnsafe(HirId), } -#[derive(AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] #[args(<'tcx, S: UnderOwnerState<'tcx> + HasMir<'tcx>>, from: rustc_middle::mir::Operand<'tcx>, state: S as s)] pub enum Operand { Copy(Place), @@ -191,22 +195,25 @@ pub enum Operand { Constant(Constant), } +#[cfg(feature = "rustc")] impl Operand { pub(crate) fn ty(&self) -> &Ty { match self { Operand::Copy(p) | Operand::Move(p) => &p.ty, - Operand::Constant(c) => &c.literal.typ, + Operand::Constant(c) => &c.const_.typ, } } } -#[derive(AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] #[args(<'tcx, S: UnderOwnerState<'tcx> + HasMir<'tcx>>, from: rustc_middle::mir::Terminator<'tcx>, state: S as s)] pub struct Terminator { pub source_info: SourceInfo, pub kind: TerminatorKind, } +#[cfg(feature = "rustc")] pub(crate) fn get_function_from_def_id_and_generics<'tcx, S: BaseState<'tcx> + HasOwnerId>( s: &S, def_id: rustc_hir::def_id::DefId, @@ -322,6 +329,7 @@ pub(crate) fn get_function_from_def_id_and_generics<'tcx, S: BaseState<'tcx> + H /// The [Operand] comes from a [TerminatorKind::Call]. /// Only supports calls to top-level functions (which are considered as constants /// by rustc); doesn't support closures for now. +#[cfg(feature = "rustc")] fn get_function_from_operand<'tcx, S: UnderOwnerState<'tcx> + HasMir<'tcx>>( s: &S, func: &rustc_middle::mir::Operand<'tcx>, @@ -329,17 +337,16 @@ fn get_function_from_operand<'tcx, S: UnderOwnerState<'tcx> + HasMir<'tcx>>( use std::ops::Deref; // Match on the func operand: it should be a constant as we don't support // closures for now. - use rustc_middle::mir::{ConstantKind, Operand}; + use rustc_middle::mir::{Const, Operand}; use rustc_middle::ty::TyKind; match func { Operand::Constant(c) => { // Regular function case let c = c.deref(); - let (def_id, generics) = match &c.literal { - ConstantKind::Ty(c) => { + let (def_id, generics) = match &c.const_ { + Const::Ty(c_ty, _c) => { // The type of the constant should be a FnDef, allowing // us to retrieve the function's identifier and instantiation. - let c_ty = c.ty(); assert!(c_ty.is_fn()); match c_ty.kind() { TyKind::FnDef(def_id, generics) => (*def_id, *generics), @@ -348,7 +355,7 @@ fn get_function_from_operand<'tcx, S: UnderOwnerState<'tcx> + HasMir<'tcx>>( } } } - ConstantKind::Val(_, c_ty) => { + Const::Val(_, c_ty) => { // Same as for the `Ty` case above assert!(c_ty.is_fn()); match c_ty.kind() { @@ -358,7 +365,7 @@ fn get_function_from_operand<'tcx, S: UnderOwnerState<'tcx> + HasMir<'tcx>>( } } } - ConstantKind::Unevaluated(_, _) => { + Const::Unevaluated(_, _) => { unimplemented!(); } }; @@ -390,6 +397,7 @@ fn get_function_from_operand<'tcx, S: UnderOwnerState<'tcx> + HasMir<'tcx>>( } } +#[cfg(feature = "rustc")] fn translate_terminator_kind_call<'tcx, S: BaseState<'tcx> + HasMir<'tcx> + HasOwnerId>( s: &S, terminator: &rustc_middle::mir::TerminatorKind<'tcx>, @@ -424,15 +432,15 @@ fn translate_terminator_kind_call<'tcx, S: BaseState<'tcx> + HasMir<'tcx> + HasO } // We don't use the LitIntType on purpose (we don't want the "unsuffixed" case) -#[derive( - Clone, Copy, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Clone, Copy, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum IntUintTy { Int(IntTy), Uint(UintTy), } -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub struct ScalarInt { /// Little-endian representation of the integer pub data_le_bytes: [u8; 16], @@ -441,6 +449,7 @@ pub struct ScalarInt { // TODO: naming conventions: is "translate" ok? /// Translate switch targets +#[cfg(feature = "rustc")] fn translate_switch_targets<'tcx, S: UnderOwnerState<'tcx>>( s: &S, switch_ty: &Ty, @@ -491,7 +500,8 @@ fn translate_switch_targets<'tcx, S: UnderOwnerState<'tcx>>( } } -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub enum SwitchTargets { /// Gives the `if` block and the `else` block If(BasicBlock, BasicBlock), @@ -501,7 +511,8 @@ pub enum SwitchTargets { SwitchInt(IntUintTy, Vec<(ScalarInt, BasicBlock)>, BasicBlock), } -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub enum FunOperand { /// Call to a top-level function designated by its id Id(DefId), @@ -509,7 +520,8 @@ pub enum FunOperand { Move(Place), } -#[derive(AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] #[args(<'tcx, S: UnderOwnerState<'tcx> + HasMir<'tcx>>, from: rustc_middle::mir::TerminatorKind<'tcx>, state: S as s)] pub enum TerminatorKind { Goto { @@ -548,7 +560,7 @@ pub enum TerminatorKind { /// relevant to the method (and not the trait) if it is a trait method /// call. See [ParamsInfo] for the full details. generics: Vec, - args: Vec, + args: Vec>, destination: Place, target: Option, unwind: UnwindAction, @@ -557,6 +569,11 @@ pub enum TerminatorKind { trait_refs: Vec, trait_info: Option, }, + TailCall { + func: Operand, + args: Vec>, + fn_span: Span, + }, Assert { cond: Operand, expected: bool, @@ -570,7 +587,7 @@ pub enum TerminatorKind { resume_arg: Place, drop: Option, }, - GeneratorDrop, + CoroutineDrop, FalseEdge { real_target: BasicBlock, imaginary_target: BasicBlock, @@ -586,12 +603,13 @@ pub enum TerminatorKind { operands: Vec, options: InlineAsmOptions, line_spans: Vec, - destination: Option, + targets: Vec, unwind: UnwindAction, }, } -#[derive(AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] #[args(<'tcx, S: UnderOwnerState<'tcx> + HasMir<'tcx>>, from: rustc_middle::mir::Statement<'tcx>, state: S as s)] pub struct Statement { pub source_info: SourceInfo, @@ -599,7 +617,8 @@ pub struct Statement { pub kind: Box, } -#[derive(AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] #[args(<'tcx, S: UnderOwnerState<'tcx> + HasMir<'tcx>>, from: rustc_middle::mir::StatementKind<'tcx>, state: S as s)] pub enum StatementKind { Assign((Place, Rvalue)), @@ -614,20 +633,22 @@ pub enum StatementKind { Retag(RetagKind, Place), PlaceMention(Place), AscribeUserType((Place, UserTypeProjection), Variance), - Coverage(Coverage), + Coverage(CoverageKind), Intrinsic(NonDivergingIntrinsic), ConstEvalCounter, Nop, } -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub struct Place { /// The type of the element on which we apply the projection given by `kind` pub ty: Ty, pub kind: PlaceKind, } -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub enum PlaceKind { Local(Local), Projection { @@ -636,7 +657,8 @@ pub enum PlaceKind { }, } -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub enum ProjectionElemFieldKind { Tuple(FieldIdx), Adt { @@ -648,7 +670,8 @@ pub enum ProjectionElemFieldKind { ClosureState(FieldIdx), } -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub enum ProjectionElem { Deref, Field(ProjectionElemFieldKind), @@ -668,6 +691,7 @@ pub enum ProjectionElem { } // refactor +#[cfg(feature = "rustc")] impl<'tcx, S: UnderOwnerState<'tcx> + HasMir<'tcx>> SInto for rustc_middle::mir::Place<'tcx> { @@ -683,29 +707,30 @@ impl<'tcx, S: UnderOwnerState<'tcx> + HasMir<'tcx>> SInto let cur_ty = current_ty.clone(); let cur_kind = current_kind.clone(); use rustc_middle::ty::TyKind; - let mk_field = |index: &rustc_abi::FieldIdx, - variant_idx: Option| { - ProjectionElem::Field(match cur_ty.kind() { - TyKind::Adt(adt_def, _) => { - assert!( - (adt_def.is_struct() && variant_idx.is_none()) - || (adt_def.is_enum() && variant_idx.is_some()) - ); - ProjectionElemFieldKind::Adt { - typ: adt_def.did().sinto(s), - variant: variant_idx.map(|id| id.sinto(s)), - index: index.sinto(s), + let mk_field = + |index: &rustc_target::abi::FieldIdx, + variant_idx: Option| { + ProjectionElem::Field(match cur_ty.kind() { + TyKind::Adt(adt_def, _) => { + assert!( + (adt_def.is_struct() && variant_idx.is_none()) + || (adt_def.is_enum() && variant_idx.is_some()) + ); + ProjectionElemFieldKind::Adt { + typ: adt_def.did().sinto(s), + variant: variant_idx.map(|id| id.sinto(s)), + index: index.sinto(s), + } } - } - TyKind::Tuple(_types) => ProjectionElemFieldKind::Tuple(index.sinto(s)), - ty_kind => { - supposely_unreachable_fatal!( - s, "ProjectionElemFieldBadType"; - {index, ty_kind, variant_idx, &cur_ty, &cur_kind} - ); - } - }) - }; + TyKind::Tuple(_types) => ProjectionElemFieldKind::Tuple(index.sinto(s)), + ty_kind => { + supposely_unreachable_fatal!( + s, "ProjectionElemFieldBadType"; + {index, ty_kind, variant_idx, &cur_ty, &cur_kind} + ); + } + }) + }; let elem_kind: ProjectionElem = match elems { [Downcast(_, variant_idx), Field(index, ty), rest @ ..] => { elems = rest; @@ -789,6 +814,9 @@ impl<'tcx, S: UnderOwnerState<'tcx> + HasMir<'tcx>> SInto current_ty = ty.clone(); ProjectionElem::OpaqueCast } + // This is used for casts to a subtype, e.g. between `for<‘a> fn(&’a ())` + // and `fn(‘static ())` (according to @compiler-errors on Zulip). + Subtype { .. } => panic!("unexpected Subtype"), Downcast { .. } => panic!("unexpected Downcast"), } } @@ -810,43 +838,18 @@ impl<'tcx, S: UnderOwnerState<'tcx> + HasMir<'tcx>> SInto } } -#[derive( - Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] -pub struct MirFnSig { - pub inputs: Vec, - pub output: Ty, - pub c_variadic: bool, - pub unsafety: Unsafety, - pub abi: Abi, -} - -pub type MirPolyFnSig = Binder; - -impl<'tcx, S: BaseState<'tcx> + HasOwnerId> SInto for rustc_middle::ty::FnSig<'tcx> { - fn sinto(&self, s: &S) -> MirFnSig { - let inputs = self.inputs().sinto(s); - let output = self.output().sinto(s); - MirFnSig { - inputs, - output, - c_variadic: self.c_variadic, - unsafety: self.unsafety.sinto(s), - abi: self.abi.sinto(s), - } - } -} - // TODO: we need this function because sometimes, Rust doesn't infer the proper // typeclass instance. +#[cfg(feature = "rustc")] pub(crate) fn poly_fn_sig_to_mir_poly_fn_sig<'tcx, S: BaseState<'tcx> + HasOwnerId>( sig: &rustc_middle::ty::PolyFnSig<'tcx>, s: &S, -) -> MirPolyFnSig { +) -> PolyFnSig { sig.sinto(s) } -#[derive(AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] #[args(<'tcx, S: UnderOwnerState<'tcx> + HasMir<'tcx>>, from: rustc_middle::mir::AggregateKind<'tcx>, state: S as s)] pub enum AggregateKind { Array(Ty), @@ -895,15 +898,18 @@ pub enum AggregateKind { let trait_refs = solve_item_traits(s, param_env, *rust_id, generics, Some(predicates)); AggregateKind::Closure(def_id, parent_generics.sinto(s), trait_refs, sig) })] - Closure(DefId, Vec, Vec, MirPolyFnSig), - Generator(DefId, Vec, Movability), + Closure(DefId, Vec, Vec, PolyFnSig), + Coroutine(DefId, Vec), + CoroutineClosure(DefId, Vec), + RawPtr(Ty, Mutability), } -#[derive(AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] #[args(<'tcx, S: UnderOwnerState<'tcx> + HasMir<'tcx>>, from: rustc_middle::mir::CastKind, state: S as s)] pub enum CastKind { - PointerExposeAddress, - PointerFromExposedAddress, + PointerExposeProvenance, + PointerWithExposedProvenance, PointerCoercion(PointerCoercion), DynStar, IntToInt, @@ -915,15 +921,18 @@ pub enum CastKind { Transmute, } -#[derive(AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] #[args(<'tcx, S: UnderOwnerState<'tcx> + HasMir<'tcx>>, from: rustc_middle::mir::NullOp<'tcx>, state: S as s)] pub enum NullOp { SizeOf, AlignOf, - OffsetOf(Vec), + OffsetOf(Vec<(usize, FieldIdx)>), + UbChecks, } -#[derive(AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] #[args(<'tcx, S: UnderOwnerState<'tcx> + HasMir<'tcx>>, from: rustc_middle::mir::Rvalue<'tcx>, state: S as s)] pub enum Rvalue { Use(Operand), @@ -940,7 +949,6 @@ pub enum Rvalue { Len(Place), Cast(CastKind, Operand, Ty), BinaryOp(BinOp, (Operand, Operand)), - CheckedBinaryOp(BinOp, (Operand, Operand)), NullaryOp(NullOp, Ty), UnaryOp(UnOp, Operand), Discriminant(Place), @@ -949,7 +957,8 @@ pub enum Rvalue { CopyForDeref(Place), } -#[derive(AdtInto, Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] #[args(<'tcx, S: UnderOwnerState<'tcx> + HasMir<'tcx>>, from: rustc_middle::mir::BasicBlockData<'tcx>, state: S as s)] pub struct BasicBlockData { pub statements: Vec, @@ -964,9 +973,9 @@ make_idx_wrapper!(rustc_middle::mir, BasicBlock); make_idx_wrapper!(rustc_middle::mir, SourceScope); make_idx_wrapper!(rustc_middle::mir, Local); make_idx_wrapper!(rustc_middle::ty, UserTypeAnnotationIndex); -make_idx_wrapper!(rustc_abi, FieldIdx); +make_idx_wrapper!(rustc_target::abi, FieldIdx); -sinto_todo!(rustc_middle::ty, InstanceDef<'tcx>); +sinto_todo!(rustc_middle::ty, InstanceKind<'tcx>); sinto_todo!(rustc_middle::mir, UserTypeProjections); sinto_todo!(rustc_middle::mir, LocalInfo<'tcx>); sinto_todo!(rustc_ast::ast, InlineAsmTemplatePiece); @@ -976,11 +985,11 @@ sinto_todo!(rustc_middle::mir, AssertMessage<'tcx>); sinto_todo!(rustc_middle::mir, UnwindAction); sinto_todo!(rustc_middle::mir, FakeReadCause); sinto_todo!(rustc_middle::mir, RetagKind); -sinto_todo!(rustc_middle::mir, Coverage); sinto_todo!(rustc_middle::mir, NonDivergingIntrinsic<'tcx>); sinto_todo!(rustc_middle::mir, UserTypeProjection); sinto_todo!(rustc_middle::mir, MirSource<'tcx>); -sinto_todo!(rustc_middle::mir, GeneratorInfo<'tcx>); +sinto_todo!(rustc_middle::mir, CoroutineInfo<'tcx>); sinto_todo!(rustc_middle::mir, VarDebugInfo<'tcx>); sinto_todo!(rustc_middle::mir, CallSource); +sinto_todo!(rustc_middle::mir::coverage, CoverageKind); sinto_todo!(rustc_span, ErrorGuaranteed); diff --git a/frontend/exporter/src/types/mir_traits.rs b/frontend/exporter/src/types/mir_traits.rs index c0d3c39dd..6e8d96d8b 100644 --- a/frontend/exporter/src/types/mir_traits.rs +++ b/frontend/exporter/src/types/mir_traits.rs @@ -77,7 +77,7 @@ pub fn solve_item_traits<'tcx, S: UnderOwnerState<'tcx>>( // variables. // Remark: there is also EarlyBinder::subst(...) let value = rustc_middle::ty::EarlyBinder::bind(pred_kind.skip_binder()); - tcx.subst_and_normalize_erasing_regions(generics, param_env, value) + tcx.instantiate_and_normalize_erasing_regions(generics, param_env, value) }; // Explore only the trait predicates @@ -144,7 +144,8 @@ pub fn solve_item_traits<'tcx, S: UnderOwnerState<'tcx>>( /// or a trait definition inside an impl/trait block. However it is possible /// to define an impl/trait inside a function, which can itself be inside a /// block, leading to nested impl blocks. -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub struct ParamsInfo { /// The total number of generic parameters (regions + types + consts). /// We do not consider the trait clauses as generic parameters. @@ -174,9 +175,9 @@ pub fn get_params_info<'tcx, S: BaseState<'tcx> + HasOwnerId>( let mut num_trait_type_constraints = 0; let generics = tcx.generics_of(def_id); - let num_generic_params = generics.params.len(); + let num_generic_params = generics.own_params.len(); use rustc_middle::ty::GenericParamDefKind; - for param in &generics.params { + for param in &generics.own_params { match param.kind { GenericParamDefKind::Lifetime => num_region_params += 1, GenericParamDefKind::Type { .. } => num_type_params += 1, @@ -213,15 +214,3 @@ pub fn get_params_info<'tcx, S: BaseState<'tcx> + HasOwnerId>( num_trait_type_constraints, } } - -/// Compute the parameters information for a definition's parent. See [ParamsInfo]. -pub fn get_parent_params_info<'tcx, S: BaseState<'tcx> + HasOwnerId>( - s: &S, - def_id: rustc_hir::def_id::DefId, -) -> Option { - s.base() - .tcx - .generics_of(def_id) - .parent - .map(|parent_id| get_params_info(s, parent_id)) -} diff --git a/frontend/exporter/src/types/mod.rs b/frontend/exporter/src/types/mod.rs index 00fbdd947..9a1acfa6a 100644 --- a/frontend/exporter/src/types/mod.rs +++ b/frontend/exporter/src/types/mod.rs @@ -5,15 +5,18 @@ mod copied; mod def_id; mod index; mod mir; +#[cfg(feature = "rustc")] mod mir_traits; mod new; mod replaced; +pub(crate) mod serialize_int; mod todo; pub use copied::*; pub use def_id::*; pub use index::*; pub use mir::*; +#[cfg(feature = "rustc")] pub use mir_traits::*; pub use new::*; pub use replaced::*; diff --git a/frontend/exporter/src/types/new/full_def.rs b/frontend/exporter/src/types/new/full_def.rs new file mode 100644 index 000000000..7e4526e35 --- /dev/null +++ b/frontend/exporter/src/types/new/full_def.rs @@ -0,0 +1,435 @@ +use crate::prelude::*; + +#[cfg(feature = "rustc")] +use rustc_middle::ty; +#[cfg(feature = "rustc")] +use rustc_span::def_id::DefId as RDefId; + +/// Gathers a lot of definition information about a [`rustc_hir::def_id::DefId`]. +#[derive(AdtInto)] +#[args(<'tcx, S: BaseState<'tcx>>, from: rustc_hir::def_id::DefId, state: S as s)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub struct FullDef { + #[value(self.sinto(s))] + pub def_id: DefId, + #[value(s.base().tcx.opt_parent(*self).sinto(s))] + pub parent: Option, + #[value(s.base().tcx.def_span(*self).sinto(s))] + pub span: Span, + #[value(s.base().tcx.get_attrs_unchecked(*self).sinto(s))] + /// Attributes on this definition, if applicable. + pub attributes: Vec, + #[value(get_def_visibility(s, *self))] + /// Visibility of the definition, for definitions where this makes sense. + pub visibility: Option, + #[value(s.base().tcx.as_lang_item(*self).map(|litem| litem.name()).sinto(s))] + /// If this definition is a lang item, we store the identifier, e.g. `sized`. + pub lang_item: Option, + #[value(s.base().tcx.get_diagnostic_name(*self).sinto(s))] + /// If this definition is a diagnostic item, we store the identifier, e.g. `box_new`. + pub diagnostic_item: Option, + #[value({ + let state_with_id = State { thir: (), mir: (), owner_id: *self, base: s.base() }; + s.base().tcx.def_kind(*self).sinto(&state_with_id) + })] + pub kind: FullDefKind, +} + +/// Imbues [`rustc_hir::def::DefKind`] with a lot of extra information. +/// Important: the `owner_id()` must be the id of this definition. +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::def::DefKind, state: S as s)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub enum FullDefKind { + // Type namespace + Mod, + /// Refers to the struct definition, [`DefKind::Ctor`] refers to its constructor if it exists. + Struct { + #[value(s.base().tcx.generics_of(s.owner_id()).sinto(s))] + generics: TyGenerics, + #[value(get_generic_predicates(s, s.owner_id()))] + predicates: GenericPredicates, + #[value(s.base().tcx.adt_def(s.owner_id()).sinto(s))] + def: AdtDef, + }, + Union { + #[value(s.base().tcx.generics_of(s.owner_id()).sinto(s))] + generics: TyGenerics, + #[value(get_generic_predicates(s, s.owner_id()))] + predicates: GenericPredicates, + #[value(s.base().tcx.adt_def(s.owner_id()).sinto(s))] + def: AdtDef, + }, + Enum { + #[value(s.base().tcx.generics_of(s.owner_id()).sinto(s))] + generics: TyGenerics, + #[value(get_generic_predicates(s, s.owner_id()))] + predicates: GenericPredicates, + #[value(s.base().tcx.adt_def(s.owner_id()).sinto(s))] + def: AdtDef, + }, + /// Refers to the variant definition, [`DefKind::Ctor`] refers to its constructor if it exists. + Variant, + Trait { + #[value(s.base().tcx.generics_of(s.owner_id()).sinto(s))] + generics: TyGenerics, + #[value(get_generic_predicates(s, s.owner_id()))] + predicates: GenericPredicates, + // `predicates_of` has the special `Self: Trait` clause as its last element. + #[value({ + let (clause, _) = s.base().tcx.predicates_of(s.owner_id()).predicates.last().unwrap(); + let Some(ty::ClauseKind::Trait(trait_ref)) = clause.kind().no_bound_vars() else { + panic!() + }; + trait_ref.sinto(s) + })] + self_predicate: TraitPredicate, + /// Associated items, in definition order. + #[value(s.base().tcx.associated_items(s.owner_id()).in_definition_order().collect::>().sinto(s))] + items: Vec, + }, + /// Type alias: `type Foo = Bar;` + TyAlias { + #[value(s.base().tcx.generics_of(s.owner_id()).sinto(s))] + generics: TyGenerics, + #[value(get_generic_predicates(s, s.owner_id()))] + predicates: GenericPredicates, + /// `Some` if the item is in the local crate. + #[value(s.base().tcx.hir().get_if_local(s.owner_id()).map(|node| { + let rustc_hir::Node::Item(item) = node else { unreachable!() }; + let rustc_hir::ItemKind::TyAlias(ty, _generics) = &item.kind else { unreachable!() }; + ty.sinto(s) + }))] + ty: Option, + }, + /// Type from an `extern` block. + ForeignTy, + /// Trait alias: `trait IntIterator = Iterator;` + TraitAlias, + /// Associated type: `trait MyTrait { type Assoc; }` + AssocTy { + #[value(s.base().tcx.parent(s.owner_id()).sinto(s))] + parent: DefId, + #[value(s.base().tcx.generics_of(s.owner_id()).sinto(s))] + generics: TyGenerics, + #[value(get_item_predicates(s, s.owner_id()))] + predicates: GenericPredicates, + #[value(s.base().tcx.associated_item(s.owner_id()).sinto(s))] + associated_item: AssocItem, + #[value({ + let tcx = s.base().tcx; + if tcx.defaultness(s.owner_id()).has_value() { + Some(tcx.type_of(s.owner_id()).instantiate_identity().sinto(s)) + } else { + None + } + })] + value: Option, + }, + /// Type parameter: the `T` in `struct Vec { ... }` + TyParam, + + // Value namespace + Fn { + #[value(s.base().tcx.generics_of(s.owner_id()).sinto(s))] + generics: TyGenerics, + #[value(get_generic_predicates(s, s.owner_id()))] + predicates: GenericPredicates, + #[value(s.base().tcx.codegen_fn_attrs(s.owner_id()).inline.sinto(s))] + inline: InlineAttr, + #[value(s.base().tcx.fn_sig(s.owner_id()).instantiate_identity().sinto(s))] + sig: PolyFnSig, + }, + /// Associated function: `impl MyStruct { fn associated() {} }` or `trait Foo { fn associated() + /// {} }` + AssocFn { + #[value(s.base().tcx.parent(s.owner_id()).sinto(s))] + parent: DefId, + #[value(s.base().tcx.associated_item(s.owner_id()).sinto(s))] + associated_item: AssocItem, + #[value(s.base().tcx.generics_of(s.owner_id()).sinto(s))] + generics: TyGenerics, + #[value(get_generic_predicates(s, s.owner_id()))] + predicates: GenericPredicates, + #[value(s.base().tcx.codegen_fn_attrs(s.owner_id()).inline.sinto(s))] + inline: InlineAttr, + #[value(s.base().tcx.fn_sig(s.owner_id()).instantiate_identity().sinto(s))] + sig: PolyFnSig, + }, + /// A closure, coroutine, or coroutine-closure. + /// + /// Note: the (early-bound) generics of a closure are the same as those of the item in which it + /// is defined. + Closure { + /// The enclosing item. Note: this item could itself be a closure; to get the generics, you + /// might have to recurse through several layers of parents until you find a function or + /// constant. + #[value(s.base().tcx.parent(s.owner_id()).sinto(s))] + parent: DefId, + #[value({ + let fun_type = s.base().tcx.type_of(s.owner_id()).instantiate_identity(); + match fun_type.kind() { + ty::TyKind::Closure(_, args) => args.as_closure().sinto(s), + _ => unreachable!(), + } + })] + args: ClosureArgs, + }, + Const { + #[value(s.base().tcx.generics_of(s.owner_id()).sinto(s))] + generics: TyGenerics, + #[value(get_generic_predicates(s, s.owner_id()))] + predicates: GenericPredicates, + #[value(s.base().tcx.type_of(s.owner_id()).instantiate_identity().sinto(s))] + ty: Ty, + }, + /// Associated constant: `trait MyTrait { const ASSOC: usize; }` + AssocConst { + #[value(s.base().tcx.parent(s.owner_id()).sinto(s))] + parent: DefId, + #[value(s.base().tcx.associated_item(s.owner_id()).sinto(s))] + associated_item: AssocItem, + #[value(s.base().tcx.generics_of(s.owner_id()).sinto(s))] + generics: TyGenerics, + #[value(get_generic_predicates(s, s.owner_id()))] + predicates: GenericPredicates, + #[value(s.base().tcx.type_of(s.owner_id()).instantiate_identity().sinto(s))] + ty: Ty, + }, + Static { + /// Whether it's a `unsafe static`, `safe static` (inside extern only) or just a `static`. + safety: Safety, + /// Whether it's a `static mut` or just a `static`. + mutability: Mutability, + /// Whether it's an anonymous static generated for nested allocations. + nested: bool, + #[value(s.base().tcx.generics_of(s.owner_id()).sinto(s))] + generics: TyGenerics, + #[value(get_generic_predicates(s, s.owner_id()))] + predicates: GenericPredicates, + #[value(s.base().tcx.type_of(s.owner_id()).instantiate_identity().sinto(s))] + ty: Ty, + }, + /// Constant generic parameter: `struct Foo { ... }` + ConstParam, + /// Refers to the struct or enum variant's constructor. + Ctor(CtorOf, CtorKind), + + // Macro namespace + Macro(MacroKind), + + // Not namespaced (or they are, but we don't treat them so) + ExternCrate, + Use, + /// An `extern` block. + ForeignMod, + /// Anonymous constant, e.g. the `1 + 2` in `[u8; 1 + 2]` + AnonConst, + /// An inline constant, e.g. `const { 1 + 2 }` + InlineConst, + /// Opaque type, aka `impl Trait`. + OpaqueTy, + Impl { + #[value(s.base().tcx.generics_of(s.owner_id()).sinto(s))] + generics: TyGenerics, + #[value(get_generic_predicates(s, s.owner_id()))] + predicates: GenericPredicates, + #[value(s.base().tcx.impl_subject(s.owner_id()).instantiate_identity().sinto(s))] + impl_subject: ImplSubject, + /// Associated items, in definition order. + #[value(s.base().tcx.associated_items(s.owner_id()).in_definition_order().collect::>().sinto(s))] + items: Vec, + }, + /// A field in a struct, enum or union. e.g. + /// - `bar` in `struct Foo { bar: u8 }` + /// - `Foo::Bar::0` in `enum Foo { Bar(u8) }` + Field, + /// Lifetime parameter: the `'a` in `struct Foo<'a> { ... }` + LifetimeParam, + /// A use of `global_asm!`. + GlobalAsm, +} + +impl FullDef { + pub fn kind(&self) -> &FullDefKind { + &self.kind + } + + /// Returns the generics and predicates for definitions that have those. + pub fn generics(&self) -> Option<(&TyGenerics, &GenericPredicates)> { + use FullDefKind::*; + match &self.kind { + Struct { + generics, + predicates, + .. + } + | Union { + generics, + predicates, + .. + } + | Enum { + generics, + predicates, + .. + } + | Trait { + generics, + predicates, + .. + } + | TyAlias { + generics, + predicates, + .. + } + | AssocTy { + generics, + predicates, + .. + } + | Fn { + generics, + predicates, + .. + } + | AssocFn { + generics, + predicates, + .. + } + | Const { + generics, + predicates, + .. + } + | AssocConst { + generics, + predicates, + .. + } + | Static { + generics, + predicates, + .. + } + | Impl { + generics, + predicates, + .. + } => Some((generics, predicates)), + _ => None, + } + } +} + +/// Gets the visibility (`pub` or not) of the definition. Returns `None` for defs that don't have a +/// meaningful visibility. +#[cfg(feature = "rustc")] +fn get_def_visibility<'tcx, S: BaseState<'tcx>>(s: &S, def_id: RDefId) -> Option { + use rustc_hir::def::DefKind::*; + let tcx = s.base().tcx; + match tcx.def_kind(def_id) { + AssocConst + | AssocFn + | Const + | Enum + | Field + | Fn + | ForeignTy + | Macro { .. } + | Mod + | Static { .. } + | Struct + | Trait + | TraitAlias + | TyAlias { .. } + | Union + | Use + | Variant => Some(tcx.visibility(def_id).is_public()), + // These kinds don't have visibility modifiers (which would cause `visibility` to panic). + AnonConst + | AssocTy + | Closure + | ConstParam + | Ctor { .. } + | ExternCrate + | ForeignMod + | GlobalAsm + | Impl { .. } + | InlineConst + | LifetimeParam + | OpaqueTy + | TyParam => None, + } +} + +/// This normalizes trait clauses before calling `sinto` on them. This is a bit of a hack required +/// by charon for now. We can't normalize all clauses as this would lose region information in +/// outlives clauses. +/// TODO: clarify normalization in charon (https://github.com/AeneasVerif/charon/issues/300). +#[cfg(feature = "rustc")] +fn normalize_trait_clauses<'tcx, S: UnderOwnerState<'tcx>>( + s: &S, + predicates: &[(ty::Clause<'tcx>, rustc_span::Span)], +) -> Vec<(Predicate, Span)> { + let predicates: Vec<_> = predicates + .iter() + .map(|(clause, span)| { + let mut clause = clause.clone(); + if matches!(&clause.kind().skip_binder(), ty::ClauseKind::Trait(_)) { + clause = s + .base() + .tcx + .normalize_erasing_regions(s.param_env(), clause); + } + (clause.as_predicate(), *span) + }) + .collect(); + predicates.sinto(s) +} + +/// Gets the `predicates_defined_on` the given `DefId` and processes them with +/// `normalize_trait_clauses`. +#[cfg(feature = "rustc")] +fn get_generic_predicates<'tcx, S: UnderOwnerState<'tcx>>( + s: &S, + def_id: RDefId, +) -> GenericPredicates { + // We use `predicates_defined_on` to skip the implied `Self` clause. + let predicates = s.base().tcx.predicates_defined_on(def_id); + let pred_list = normalize_trait_clauses(s, predicates.predicates); + GenericPredicates { + parent: predicates.parent.sinto(s), + predicates: pred_list, + } +} + +/// Gets the predicates defined on the given associated type and processes them with +/// `normalize_trait_clauses`. +#[cfg(feature = "rustc")] +fn get_item_predicates<'tcx, S: UnderOwnerState<'tcx>>(s: &S, def_id: RDefId) -> GenericPredicates { + let tcx = s.base().tcx; + let parent_id = tcx.parent(def_id); + // `item_bounds` cannot be called on a trait impl item, and returns empty on an inherent impl + // item. So we only call it for trait decl items. + let predicates = match tcx.def_kind(parent_id) { + rustc_hir::def::DefKind::Trait => { + // TODO: we probably want to use `explicit_item_bounds` instead, but should do so + // consistently. + let clauses = tcx.item_bounds(def_id).instantiate_identity(); + use crate::rustc_middle::query::Key; + let span = clauses.default_span(tcx); + clauses.iter().map(|c| (c, span)).collect::>() + } + _ => Vec::new(), + }; + let predicates = normalize_trait_clauses(s, predicates.as_slice()); + GenericPredicates { + parent: Some(parent_id.sinto(s)), + predicates, + } +} diff --git a/frontend/exporter/src/types/new/impl_infos.rs b/frontend/exporter/src/types/new/impl_infos.rs new file mode 100644 index 000000000..971184b45 --- /dev/null +++ b/frontend/exporter/src/types/new/impl_infos.rs @@ -0,0 +1,12 @@ +use crate::prelude::*; + +/// Meta-informations about an `impl TRAIT for +/// TYPE where PREDICATES {}` +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub struct ImplInfos { + pub generics: TyGenerics, + pub clauses: Vec<(Clause, Span)>, + pub typ: Ty, + pub trait_ref: Option, +} diff --git a/frontend/exporter/src/types/new/item_attributes.rs b/frontend/exporter/src/types/new/item_attributes.rs index bfaa141d1..673e8b04f 100644 --- a/frontend/exporter/src/types/new/item_attributes.rs +++ b/frontend/exporter/src/types/new/item_attributes.rs @@ -1,6 +1,7 @@ use crate::prelude::*; -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub struct ItemAttributes { attributes: Vec, parent_attributes: Vec, @@ -15,11 +16,13 @@ impl ItemAttributes { } } +#[cfg(feature = "rustc")] lazy_static::lazy_static! { pub static ref CORE_EXTRACTION_MODE: bool = std::env::var_os("HAX_CORE_EXTRACTION_MODE") == Some("on".into()); } +#[cfg(feature = "rustc")] impl ItemAttributes { pub fn from_owner_id<'tcx, S: BaseState<'tcx>>( s: &S, diff --git a/frontend/exporter/src/types/new/mod.rs b/frontend/exporter/src/types/new/mod.rs index ca52e55ac..c53569f9b 100644 --- a/frontend/exporter/src/types/new/mod.rs +++ b/frontend/exporter/src/types/new/mod.rs @@ -1,10 +1,14 @@ //! This module contains type definitions that have no equivalent in //! Rustc. +mod full_def; +mod impl_infos; mod item_attributes; mod predicate_id; mod typed_constant_kind; +pub use full_def::*; +pub use impl_infos::*; pub use item_attributes::*; pub use predicate_id::*; pub use typed_constant_kind::*; diff --git a/frontend/exporter/src/types/new/predicate_id.rs b/frontend/exporter/src/types/new/predicate_id.rs index 04fa8b49d..ab34ec546 100644 --- a/frontend/exporter/src/types/new/predicate_id.rs +++ b/frontend/exporter/src/types/new/predicate_id.rs @@ -1,65 +1,72 @@ use crate::prelude::*; -use rustc_middle::ty; -#[derive( - Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord, -)] +#[derive_group(Serializers)] +#[derive(Copy, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] #[serde(transparent)] /// A `PredicateId` is a unique identifier for a clause or a /// predicate. It is computed by hashing predicates and clause in a /// uniform and deterministic way. pub struct PredicateId(u64); -/// Implemented by anything that can be assimilated to a predicate. -pub trait IntoPredicateId<'tcx, S: UnderOwnerState<'tcx>> { - /// Compute a consistent `PredicateId` - fn predicate_id(&self, s: &S) -> PredicateId; -} +#[cfg(feature = "rustc")] +pub use self::rustc::*; +#[cfg(feature = "rustc")] +mod rustc { + use super::*; + use rustc_middle::ty; + /// Implemented by anything that can be assimilated to a predicate. + pub trait IntoPredicateId<'tcx, S: UnderOwnerState<'tcx>> { + /// Compute a consistent `PredicateId` + fn predicate_id(&self, s: &S) -> PredicateId; + } -impl<'tcx, S: UnderOwnerState<'tcx>> IntoPredicateId<'tcx, S> for ty::Clause<'tcx> { - fn predicate_id(&self, s: &S) -> PredicateId { - self.as_predicate().predicate_id(s) + impl<'tcx, S: UnderOwnerState<'tcx>> IntoPredicateId<'tcx, S> for ty::Clause<'tcx> { + fn predicate_id(&self, s: &S) -> PredicateId { + self.as_predicate().predicate_id(s) + } } -} -impl<'tcx, S: UnderOwnerState<'tcx>> IntoPredicateId<'tcx, S> for ty::Predicate<'tcx> { - fn predicate_id(&self, s: &S) -> PredicateId { - // Here, we need to be careful about not hashing a `crate::Predicate`, - // but `crate::Binder` instead, - // otherwise we would get into a infinite recursion. - let poly_kind: Binder = self.kind().sinto(s); - PredicateId(deterministic_hash(&poly_kind)) + impl<'tcx, S: UnderOwnerState<'tcx>> IntoPredicateId<'tcx, S> for ty::Predicate<'tcx> { + #[tracing::instrument(level = "trace", skip(s))] + fn predicate_id(&self, s: &S) -> PredicateId { + // Here, we need to be careful about not hashing a `crate::Predicate`, + // but `crate::Binder` instead, + // otherwise we would get into a infinite recursion. + let poly_kind: Binder = self.kind().sinto(s); + PredicateId(deterministic_hash(&poly_kind)) + } } -} -impl<'tcx, S: UnderOwnerState<'tcx>> IntoPredicateId<'tcx, S> for ty::PolyTraitPredicate<'tcx> { - fn predicate_id(&self, s: &S) -> PredicateId { - use ty::ToPredicate; - let predicate: ty::Predicate<'tcx> = (*self).to_predicate(s.base().tcx); - predicate.predicate_id(s) + impl<'tcx, S: UnderOwnerState<'tcx>> IntoPredicateId<'tcx, S> for ty::PolyTraitPredicate<'tcx> { + #[tracing::instrument(level = "trace", skip(s))] + fn predicate_id(&self, s: &S) -> PredicateId { + use ty::Upcast; + let predicate: ty::Predicate<'tcx> = (*self).upcast(s.base().tcx); + predicate.predicate_id(s) + } } -} -/// A `PredicateId` can be mapped to itself via SInto. This is useful -/// for mirroring the type [`traits::search_clause::PathChunk`] as -/// [`traits::ImplExprPathChunk`]. -impl<'tcx, S: UnderOwnerState<'tcx>> SInto for PredicateId { - fn sinto(&self, _s: &S) -> PredicateId { - *self + /// A `PredicateId` can be mapped to itself via SInto. This is useful + /// for mirroring the type [`traits::search_clause::PathChunk`] as + /// [`traits::ImplExprPathChunk`]. + impl<'tcx, S: UnderOwnerState<'tcx>> SInto for PredicateId { + fn sinto(&self, _s: &S) -> PredicateId { + *self + } } -} -/// We need identifiers that are stable across different -/// architectures, different paths (which are observable from -/// `Span`s), etc. -/// Rustc's stable hash is not doing what we want here: it is sensible -/// to the environment. Instead, we first `sinto` and then hash with -/// `deterministic_hash` below. -fn deterministic_hash(x: &T) -> u64 { - use crate::deterministic_hash::DeterministicHasher; - use std::collections::hash_map::DefaultHasher; - use std::hash::Hasher; - let mut hasher = DeterministicHasher::new(DefaultHasher::new()); - x.hash(&mut hasher); - hasher.finish() + /// We need identifiers that are stable across different + /// architectures, different paths (which are observable from + /// `Span`s), etc. + /// Rustc's stable hash is not doing what we want here: it is sensible + /// to the environment. Instead, we first `sinto` and then hash with + /// `deterministic_hash` below. + fn deterministic_hash(x: &T) -> u64 { + use crate::deterministic_hash::DeterministicHasher; + use std::collections::hash_map::DefaultHasher; + use std::hash::Hasher; + let mut hasher = DeterministicHasher::new(DefaultHasher::new()); + x.hash(&mut hasher); + hasher.finish() + } } diff --git a/frontend/exporter/src/types/new/typed_constant_kind.rs b/frontend/exporter/src/types/new/typed_constant_kind.rs index 734abc240..9658b9105 100644 --- a/frontend/exporter/src/types/new/typed_constant_kind.rs +++ b/frontend/exporter/src/types/new/typed_constant_kind.rs @@ -1,13 +1,15 @@ use crate::prelude::*; -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] pub struct TypedConstantKind { pub typ: Ty, pub constant_kind: ConstantExpr, } +#[cfg(feature = "rustc")] impl<'tcx, S: BaseState<'tcx> + HasOwnerId> SInto - for rustc_middle::mir::ConstantKind<'tcx> + for rustc_middle::mir::Const<'tcx> { fn sinto(&self, s: &S) -> TypedConstantKind { TypedConstantKind { diff --git a/frontend/exporter/src/types/replaced.rs b/frontend/exporter/src/types/replaced.rs index 6af2e21af..fb4731238 100644 --- a/frontend/exporter/src/types/replaced.rs +++ b/frontend/exporter/src/types/replaced.rs @@ -1,19 +1,23 @@ -use crate::prelude::*; - pub type Path = Vec; +pub type Mutability = bool; + +#[cfg(feature = "rustc")] +mod rustc { + use super::*; + use crate::prelude::*; -impl<'t, S> SInto for rustc_span::symbol::Symbol { - fn sinto(&self, _s: &S) -> Symbol { - self.to_ident_string() + impl<'t, S> SInto for rustc_span::symbol::Symbol { + fn sinto(&self, _s: &S) -> Symbol { + self.to_ident_string() + } } -} -pub type Mutability = bool; -impl SInto for rustc_hir::Mutability { - fn sinto(&self, _s: &S) -> Mutability { - match self { - rustc_hir::Mutability::Mut => true, - _ => false, + impl SInto for rustc_hir::Mutability { + fn sinto(&self, _s: &S) -> Mutability { + match self { + rustc_hir::Mutability::Mut => true, + _ => false, + } } } } diff --git a/frontend/exporter/src/types/serialize_int.rs b/frontend/exporter/src/types/serialize_int.rs new file mode 100644 index 000000000..3d020ea3e --- /dev/null +++ b/frontend/exporter/src/types/serialize_int.rs @@ -0,0 +1,95 @@ +//! This module provides serde manual serializes/deserializers as +//! strings for u128 and i128: those types are not well supported in +//! serde (see https://github.com/serde-rs/json/issues/625). + +use serde::{de::Visitor, ser::Serialize, Deserializer, Serializer}; + +pub mod unsigned { + use super::*; + pub fn serialize(value: &u128, serializer: S) -> Result + where + S: Serializer, + { + value.to_string().serialize(serializer) + } + + pub fn deserialize<'de, D>(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_any(IntScalarVisitor) + } + + #[derive(Debug)] + struct IntScalarVisitor; + impl<'de> Visitor<'de> for IntScalarVisitor { + type Value = u128; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + dbg!(self); + formatter.write_str("expect to receive integer") + } + + fn visit_str(self, v: &str) -> Result + where + E: serde::de::Error, + { + Ok(v.parse().map_err(serde::de::Error::custom)?) + } + + fn visit_u64(self, v: u64) -> Result + where + E: serde::de::Error, + { + Ok(v as u128) + } + } +} +pub mod signed { + use super::*; + pub fn serialize(value: &i128, serializer: S) -> Result + where + S: Serializer, + { + value.to_string().serialize(serializer) + } + + pub fn deserialize<'de, D>(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_any(IntScalarVisitor) + } + + #[derive(Debug)] + struct IntScalarVisitor; + impl<'de> Visitor<'de> for IntScalarVisitor { + type Value = i128; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + dbg!(self); + formatter.write_str("expect to receive integer") + } + + fn visit_str(self, v: &str) -> Result + where + E: serde::de::Error, + { + Ok(v.parse().map_err(serde::de::Error::custom)?) + } + + fn visit_u64(self, v: u64) -> Result + where + E: serde::de::Error, + { + Ok(v as i128) + } + + fn visit_i64(self, v: i64) -> Result + where + E: serde::de::Error, + { + Ok(v as i128) + } + } +} diff --git a/frontend/exporter/src/types/todo.rs b/frontend/exporter/src/types/todo.rs index 6df174278..c164478e1 100644 --- a/frontend/exporter/src/types/todo.rs +++ b/frontend/exporter/src/types/todo.rs @@ -1,18 +1,21 @@ use crate::prelude::*; use crate::sinto_todo; sinto_todo!(rustc_middle::ty, ScalarInt); -sinto_todo!(rustc_middle::ty, ExistentialPredicate<'a>); sinto_todo!(rustc_middle::ty, AdtFlags); +sinto_todo!(rustc_middle::ty, NormalizesTo<'tcx>); sinto_todo!(rustc_abi, IntegerType); sinto_todo!(rustc_abi, ReprFlags); sinto_todo!(rustc_abi, Align); sinto_todo!(rustc_middle::mir::interpret, ConstAllocation<'a>); sinto_todo!(rustc_middle::mir, UnwindTerminateReason); sinto_todo!(rustc_ast::tokenstream, DelimSpan); +sinto_todo!(rustc_ast::tokenstream, DelimSpacing); sinto_todo!(rustc_hir::def, DefKind); sinto_todo!(rustc_hir, GenericArgs<'a> as HirGenericArgs); sinto_todo!(rustc_hir, InlineAsm<'a>); sinto_todo!(rustc_target::spec::abi, Abi); +sinto_todo!(rustc_hir, MissingLifetimeKind); +sinto_todo!(rustc_hir, QPath<'tcx>); sinto_todo!(rustc_hir, WhereRegionPredicate<'tcx>); sinto_todo!(rustc_hir, WhereEqPredicate<'tcx>); sinto_todo!(rustc_hir, OwnerId); diff --git a/frontend/exporter/src/utils.rs b/frontend/exporter/src/utils.rs index b36bc2c58..fc5691f44 100644 --- a/frontend/exporter/src/utils.rs +++ b/frontend/exporter/src/utils.rs @@ -28,11 +28,11 @@ mod internal_helpers { ($verb:ident, $s:ident, $span:expr, $message:expr) => {{ let backtrace = std::backtrace::Backtrace::capture(); eprintln!("{}", backtrace); - let mut builder = $crate::utils::_verb!($verb, $s.base().tcx.sess, $message); + let mut builder = $crate::utils::_verb!($verb, $s.base().tcx.dcx(), $message); if let Some(span) = $span { - builder.set_span(span.clone()); + builder.span(span.clone()); } - builder.code(rustc_errors::DiagnosticId::Error(format!("HaxFront"))); + builder.code(rustc_errors::codes::ErrCode::MAX); builder.note( "⚠️ This is a bug in Hax's frontend. Please report this error to https://github.com/hacspec/hax/issues with some context (e.g. the current crate)!", diff --git a/frontend/lint/Cargo.toml b/frontend/lint/Cargo.toml deleted file mode 100644 index de8502be5..000000000 --- a/frontend/lint/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "hax-lint" -version.workspace = true -authors.workspace = true -license.workspace = true -homepage.workspace = true -edition.workspace = true -repository.workspace = true -readme.workspace = true - -[package.metadata.rust-analyzer] -rustc_private=true - -[dependencies] -hax-diagnostics.workspace = true -tracing.workspace = true - -[dev-dependencies] -regex = "1" -lazy_static = "1.4" -assert_cmd = "2.0" diff --git a/frontend/lint/src/lib.rs b/frontend/lint/src/lib.rs deleted file mode 100644 index fd7287ab9..000000000 --- a/frontend/lint/src/lib.rs +++ /dev/null @@ -1,872 +0,0 @@ -#![feature(rustc_private)] - -// rustc middle -extern crate rustc_middle; -use hax_diagnostics::error; -use rustc_middle::hir::nested_filter::OnlyBodies; -use rustc_middle::ty::TyCtxt; - -// rustc hier -extern crate rustc_hir; - -use rustc_hir::{intravisit::*, *}; - -// rustc span -extern crate rustc_span; -use rustc_span::{def_id::LocalDefId, symbol::Ident, Span, Symbol}; - -// rustc session -extern crate rustc_session; -use rustc_session::Session; - -// rustc data_structures -extern crate rustc_data_structures; -use rustc_data_structures::sync::Lrc; - -// rustc ast -extern crate rustc_ast; -use rustc_ast::ast; - -#[derive(Debug, Clone, Copy)] -pub enum Type { - Rust, - Hacspec, -} - -pub struct Linter<'a, 'tcx> { - session: &'a Lrc, - tcx: TyCtxt<'tcx>, - extern_allow_list: Vec<&'static str>, - trait_block_list: Vec, - ltype: Type, -} - -impl<'a, 'tcx> Linter<'a, 'tcx> { - /// Register the linter. - pub fn register(tcx: TyCtxt<'tcx>, session: &'a Lrc, ltype: Type) { - let hir = tcx.hir(); - - let trait_block_list = vec!["FnMut"]; - let trait_block_list = trait_block_list - .into_iter() - .map(|s| s.to_string()) - .collect(); - - let mut extern_allow_list = vec!["core", "alloc", "std"]; - if matches!(ltype, Type::Hacspec) { - extern_allow_list.append(&mut vec![ - "hacspec_lib", - "secret_integers", - "abstract_integers", - ]); - } - - let mut linter = Self { - session, - tcx, - extern_allow_list, - trait_block_list, - ltype, - }; - hir.visit_all_item_likes_in_crate(&mut linter); - } -} - -fn has_attr(attrs: &[ast::Attribute], symbol: Symbol) -> bool { - attrs.iter().any(|attr| attr.has_name(symbol)) -} - -macro_rules! skip_derived_non_local { - ($self:ident, $hir_id:expr) => { - if $self.any_parent_is_automatically_derived($hir_id) { - tracing::trace!(" skipping automatically derived code"); - return; - } - if $self.non_local_hir_id($hir_id) { - error::extern_crate($self.session, $self.tcx.def_span($hir_id.owner)); - // Don't keep going - return; - } - }; -} - -macro_rules! skip_v1_lib_macros { - ($self:ident, $hir_id:expr) => { - if $self - .tcx - .def_span($hir_id.owner) - .macro_backtrace() - .any(|data| { - if let Some(parent) = data.parent_module { - tracing::trace!(" macro in {:?}", { data.parent_module }); - if $self.non_local_def_id(parent, $self.tcx.def_span($hir_id.owner)) { - return true; - } - } - false - }) - { - return; - } - }; -} - -impl<'a, 'v> Linter<'a, 'v> { - fn any_parent_has_attr(&self, hir_id: HirId, symbol: Symbol) -> bool { - let map = &self.tcx.hir(); - let mut prev_enclosing_node = None; - let mut enclosing_node = hir_id; - while Some(enclosing_node) != prev_enclosing_node { - if has_attr(map.attrs(enclosing_node), symbol) { - return true; - } - prev_enclosing_node = Some(enclosing_node); - enclosing_node = map.get_parent_item(enclosing_node).into(); - } - - false - } - - fn any_parent_is_automatically_derived(&self, hir_id: HirId) -> bool { - self.any_parent_has_attr(hir_id, rustc_span::symbol::sym::automatically_derived) - } - - /// Check and warn for non-local def ids. - /// - /// Returns true if the path is non-local. - fn non_local_def_id(&self, def_id: rustc_span::def_id::DefId, span: Span) -> bool { - if !def_id.is_local() { - tracing::trace!(" non local path at: {:?}", span); - - let krate = self.tcx.crate_name(def_id.krate); - tracing::trace!(" crate: {:?}", krate); - if self.extern_allow_list.contains(&krate.as_str()) { - // For the allow list we assume that there's a model - return true; - } - // On everything else we warn. - error::extern_crate(self.session, span); - // } - return true; - } - false - } - - /// Check and warn for non-local paths. - /// - /// Returns true if the path is non-local. - fn non_local_path(&self, qpath: &QPath) -> bool { - match qpath { - QPath::Resolved(_, path) => match path.res { - def::Res::Def(_def_kind, def_id) => self.non_local_def_id(def_id, path.span), - _ => return false, - }, - _ => return false, - } - } - - /// Check and warn for non-local hir ids. - /// - /// Returns true if the path is non-local. - fn non_local_hir_id(&self, hir_id: HirId) -> bool { - if self.non_local_def_id(hir_id.owner.to_def_id(), self.tcx.def_span(hir_id.owner)) { - return true; - } - false - } -} - -impl<'v, 'a> Visitor<'v> for Linter<'a, 'v> { - type NestedFilter = OnlyBodies; - - fn nested_visit_map(&mut self) -> Self::Map { - tracing::trace!("visiting nested map"); - self.tcx.hir() - } - - fn visit_nested_trait_item(&mut self, id: TraitItemId) { - tracing::trace!("visiting nested trait item"); - - walk_trait_item(self, self.tcx.hir().trait_item(id)); - } - fn visit_nested_impl_item(&mut self, id: ImplItemId) { - tracing::trace!("visiting nested impl item"); - - walk_impl_item(self, self.tcx.hir().impl_item(id)); - } - fn visit_nested_foreign_item(&mut self, _id: ForeignItemId) { - tracing::trace!("visiting nested foreign item"); - } - fn visit_nested_body(&mut self, id: BodyId) { - tracing::trace!("visiting nested body"); - - walk_body(self, self.tcx.hir().body(id)); - } - - fn visit_item(&mut self, i: &'v Item<'v>) { - tracing::trace!("visiting item {:?} at {:?}", i.ident.name, i.span); - skip_derived_non_local!(self, i.hir_id()); - skip_v1_lib_macros!(self, i.hir_id()); - // tracing::trace!(" item kind: {:#?}", i.kind); - - match i.kind { - ItemKind::Union(_, _) => { - // TODO: This should be an error (span_err_with_code) - error::no_union(self.session, i.span); - // self.no_union(i.span) - } - ItemKind::GlobalAsm(_) => error::no_unsafe(self.session, i.span), - ItemKind::Impl(imp) => { - // tracing::trace!(" impl {:?}", imp.self_ty.kind); - if imp.unsafety == Unsafety::Unsafe { - error::no_unsafe(self.session, i.span); - } - if let Some(of_trait) = &imp.of_trait { - let def_id = of_trait.hir_ref_id.owner.def_id.to_def_id(); - if self - .tcx - .has_attr(def_id, rustc_span::symbol::sym::automatically_derived) - { - tracing::trace!(" Skipping automatically derived implementations"); - return; - } - } - } - _ => (), - } - - // Check for foreign item - if self.non_local_def_id(i.owner_id.def_id.to_def_id(), i.span) { - // Don't keep walking. - return; - } - - // keep going - walk_item(self, i); - } - fn visit_body(&mut self, b: &'v Body<'v>) { - tracing::trace!("visiting body"); - skip_derived_non_local!(self, b.value.hir_id); - - // keep going - walk_body(self, b); - } - - /////////////// - - fn visit_id(&mut self, hir_id: HirId) { - tracing::trace!( - "visiting id {hir_id:?} from def path {:?}", - self.tcx.def_path(hir_id.owner.to_def_id()) - ); - - skip_derived_non_local!(self, hir_id); - skip_v1_lib_macros!(self, hir_id); - - // Nothing to do. - } - fn visit_name(&mut self, name: Symbol) { - tracing::trace!("visiting name {:?}", name); - // Nothing to do. - } - fn visit_ident(&mut self, ident: Ident) { - tracing::trace!("visiting ident {:?}", ident); - - // XXX: This really shouldn't be done here but earlier. - if ident.name.as_str() == "FnMut" { - error::no_fn_mut(self.session, ident.span); - return; - } - - walk_ident(self, ident) - } - fn visit_mod(&mut self, m: &'v Mod<'v>, s: Span, n: HirId) { - tracing::trace!("visiting mod {:?}", s); - - // keep going - walk_mod(self, m, n); - } - fn visit_foreign_item(&mut self, i: &'v ForeignItem<'v>) { - tracing::trace!("visiting foreign item {:?} at {:?}", i.ident, i.span); - walk_foreign_item(self, i) - } - fn visit_local(&mut self, l: &'v Local<'v>) { - tracing::trace!("visiting local {:?}", l.span); - walk_local(self, l) - } - fn visit_block(&mut self, b: &'v Block<'v>) { - tracing::trace!("visiting block {:?}", b.span); - - skip_derived_non_local!(self, b.hir_id); - - walk_block(self, b) - } - fn visit_stmt(&mut self, s: &'v Stmt<'v>) { - tracing::trace!( - "visiting stmt {:?} at {:?}", - self.tcx.opt_item_name(s.hir_id.owner.to_def_id()).unwrap(), - s.span - ); - skip_derived_non_local!(self, s.hir_id); - - match &s.kind { - StmtKind::Local(b) => { - // tracing::trace!(" local stmt"); - if let Some(init) = b.init { - match init.kind { - ExprKind::AddrOf(x, f, _s) => { - // Don't allow raw borrows (pointer) and mutable borrows. - if matches!(x, BorrowKind::Raw) || matches!(f, Mutability::Mut) { - error::mut_borrow_let(self.session, b.span) - } - } - _ => (), - } - } - if let Some(_els) = b.els {} - } - StmtKind::Item(_) => (), // tracing::trace!(" item stmt"), - StmtKind::Expr(_) => (), // tracing::trace!(" expr stmt"), - StmtKind::Semi(_) => (), // tracing::trace!(" semi stmt"), - } - - // keep going - walk_stmt(self, s); - } - fn visit_arm(&mut self, a: &'v Arm<'v>) { - tracing::trace!("visiting arm {:?}", a.span); - walk_arm(self, a) - } - fn visit_pat(&mut self, p: &'v Pat<'v>) { - tracing::trace!("visiting pat {:?}", p.span); - walk_pat(self, p) - } - fn visit_pat_field(&mut self, f: &'v PatField<'v>) { - tracing::trace!("visiting pat field {:?} at {:?}", f.ident, f.span); - walk_pat_field(self, f) - } - fn visit_array_length(&mut self, len: &'v ArrayLen) { - tracing::trace!("visiting array length"); - walk_array_len(self, len) - } - fn visit_anon_const(&mut self, c: &'v AnonConst) { - tracing::trace!("visiting anon const"); - walk_anon_const(self, c) - } - fn visit_expr(&mut self, ex: &'v Expr<'v>) { - tracing::trace!("visiting expr {:?}", ex.span); - skip_derived_non_local!(self, ex.hir_id); - // tracing::trace!(" Node: {:#?}", self.tcx.hir().find(ex.hir_id)); - - // eprintln!(" kind: {:?}", ex.kind); - // eprintln!("expr at: {:?}", self.expr_span(ex)); - - match &ex.kind { - ExprKind::Block(block, _) => match block.rules { - BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) => { - error::no_unsafe(self.session, block.span) - } - _ => (), - }, - ExprKind::Loop(_block, _label, source, span) => match source { - LoopSource::Loop | LoopSource::While => { - error::unsupported_loop(self.session, *span) - } - LoopSource::ForLoop => tracing::trace!("hir for loop"), - }, - // FIXME: where to get this from? - // ExprKind::Async(e, c, b) => self.no_async_await(b.span), - // ExprKind::Await(a) => self.no_async_await(a.span), - ExprKind::InlineAsm(p) => error::no_unsafe(self.session, p.line_spans[0]), - ExprKind::Call(expr, _exprs) => { - // tracing::trace!("call: {:#?}", expr); - if self.tcx.is_foreign_item(expr.hir_id.owner.def_id) { - tracing::trace!("foreign call: {:#?}", expr.span); - } - } - ExprKind::MethodCall(_path, expr, _exprs, _span) => { - // tracing::trace!("method call: {:#?}", path); - if self.tcx.is_foreign_item(expr.hir_id.owner.def_id) { - tracing::trace!("foreign method call: {:#?}", expr.span); - } - } - ExprKind::Path(qpath) => { - if self.non_local_path(qpath) { - // Don't keep walking. - return; - } - } - _ => (), - } - - // keep going - walk_expr(self, ex); - } - fn visit_let_expr(&mut self, lex: &'v Let<'v>) { - tracing::trace!("visiting let expr {:?}", lex.span); - walk_let_expr(self, lex) - } - fn visit_expr_field(&mut self, field: &'v ExprField<'v>) { - tracing::trace!("visiting expr field {:?}", field.ident); - walk_expr_field(self, field) - } - fn visit_ty(&mut self, t: &'v Ty<'v>) { - tracing::trace!("visiting ty {:?}", t.span); - walk_ty(self, t) - } - fn visit_generic_param(&mut self, p: &'v GenericParam<'v>) { - tracing::trace!("visiting generic param {:?}", p.span); - tracing::trace!(" name: {:?}", p.name); - - walk_generic_param(self, p) - } - fn visit_const_param_default(&mut self, _param: HirId, ct: &'v AnonConst) { - tracing::trace!("visiting const param default"); - walk_const_param_default(self, ct) - } - fn visit_generics(&mut self, g: &'v Generics<'v>) { - tracing::trace!("visiting generics {:?}", g.span); - walk_generics(self, g) - } - fn visit_where_predicate(&mut self, predicate: &'v WherePredicate<'v>) { - tracing::trace!("visiting where predicate"); - - match predicate { - WherePredicate::BoundPredicate(p) => { - // tracing::trace!(" bound predicate {:#?}", p.bounds); - for bound in p.bounds { - match bound { - GenericBound::LangItemTrait(lang_item, span, _hir_id, _generic_args) => { - // XXX: for some reason FnMut is not a lang item - tracing::trace!(" lang trait bound {:?}", span); - if matches!(lang_item, LangItem::FnMut) { - error::no_fn_mut(self.session, *span); - } - } - GenericBound::Trait(trait_ref, _bound_modifier) => { - tracing::trace!(" trait bound {:?}", trait_ref); - // tracing::trace!( - // " node {:#?}", - // self.tcx.hir().get(trait_ref.trait_ref.hir_ref_id) - // ); - } - _ => (), - } - } - } - WherePredicate::RegionPredicate(p) => error::explicit_lifetime(self.session, p.span), - WherePredicate::EqPredicate(p) => { - tracing::trace!(" eq predicate {:?}/{:?}", p.lhs_ty, p.rhs_ty); - } - } - - // keep going - walk_where_predicate(self, predicate); - } - fn visit_fn_ret_ty(&mut self, ret_ty: &'v FnRetTy<'v>) { - tracing::trace!("visiting fn ret ty"); - walk_fn_ret_ty(self, ret_ty) - } - fn visit_fn_decl(&mut self, fd: &'v FnDecl<'v>) { - tracing::trace!("visiting fn decl"); - walk_fn_decl(self, fd) - } - fn visit_fn( - &mut self, - fk: FnKind<'v>, - fd: &'v FnDecl<'v>, - b: BodyId, - span: Span, - id: LocalDefId, - ) { - tracing::trace!("visiting fn at {:?}", span); - - let hir_id = self.tcx.hir().local_def_id_to_hir_id(id); - - skip_derived_non_local!(self, hir_id); - skip_v1_lib_macros!(self, hir_id); - - fn check_ty_kind(visitor: &Linter, k: &TyKind, span: Span) { - match k { - TyKind::Ptr(_) => error::no_unsafe(visitor.session, span), - TyKind::TraitObject(_, _, _) => { - error::no_trait_objects(visitor.session, span); - } - TyKind::Ref(lifetime, ty) => { - // TODO: check lifetime. only allow anonymous - tracing::trace!(" lifetime {:?}", lifetime.ident); - // tracing::trace!(" ref ty {:#?}", ty); - - // check for mutable self. - // we have to do that here, because we know it's mut here. - if matches!(ty.mutbl, Mutability::Mut) { - if matches!(visitor.ltype, Type::Hacspec) { - // No mutability is allowed here for hacspec - error::no_mut(visitor.session, ty.ty.span); - return; - } - match &ty.ty.kind { - TyKind::Path(path) => match path { - QPath::Resolved(_ty, p) => { - if p.segments[0].ident.as_str() == "Self" { - error::no_mut_self(visitor.session, p.span) - } - } - _ => (), - }, - _ => (), - } - } - - check_ty_kind(visitor, &ty.ty.kind, span) - } - TyKind::OpaqueDef(_, _, _) => { - error::no_trait_objects(visitor.session, span); - } - TyKind::Path(path) => match path { - QPath::Resolved(ty, p) => { - if let Some(ty) = ty { - check_ty_kind(visitor, &ty.kind, span) - } - - // check for trait objects (impl in the path) - if p.segments - .iter() - .any(|s| s.ident.to_string().contains("impl")) - { - error::no_trait_objects(visitor.session, span); - } - } - QPath::TypeRelative(ty, _p) => check_ty_kind(visitor, &ty.kind, span), - QPath::LangItem(_lang_item, _span, _hir_id) => (), - }, - _ => (), - } - } - - match fk { - FnKind::ItemFn(ident, generics, header) => { - tracing::trace!(" ItemFn: {:?}", ident); - // TODO: All this should be an error (span_err_with_code) - // Unsafe functions - if header.unsafety == Unsafety::Unsafe { - error::no_unsafe(self.session, span); - } - - // async functions - if header.asyncness == IsAsync::Async { - error::no_async_await(self.session, span); - } - - // Check generics for lifetimes - for predicate in generics.predicates { - match &predicate { - WherePredicate::RegionPredicate(region) => { - error::explicit_lifetime(self.session, region.span) - } - WherePredicate::BoundPredicate(bound) => { - for bound in bound.bounds { - match bound { - GenericBound::Trait(poly_ref, _modifier) => { - let path_string = poly_ref - .trait_ref - .path - .segments - .iter() - .map(|seg| seg.ident.as_str()) - .collect::>() - .join("::"); - tracing::trace!( - " trait implementation of {:?}", - path_string - ); - - if self.trait_block_list.contains(&path_string) { - error::unsupported_item( - self.session, - poly_ref.span, - path_string, - ); - } - } - _ => (), - } - } - } - _ => (), - } - } - for param in generics.params { - match param.kind { - GenericParamKind::Lifetime { kind } => match kind { - LifetimeParamKind::Explicit => { - error::explicit_lifetime(self.session, param.span) - } - _ => (), - }, - _ => (), - } - } - } - FnKind::Method(ident, sig) => { - tracing::trace!(" Method: {:?}", ident); - // TODO: All this should be an error (span_err_with_code) - // Unsafe functions - if sig.header.unsafety == Unsafety::Unsafe { - error::no_unsafe(self.session, span); - } - - // async functions - if sig.header.asyncness == IsAsync::Async { - error::no_async_await(self.session, span); - } - - // Check method input arguments - for input in sig.decl.inputs { - check_ty_kind(self, &input.kind, input.span); - } - } - FnKind::Closure => (), - } - fd.inputs.iter().for_each(|param| { - // // No dyn/trait object - // FIXME - // tracing::trace!("fd inputs {:#?}", param); - check_ty_kind(self, ¶m.kind, param.span); - }); - - // keep going - walk_fn(self, fk, fd, b, id); - } - fn visit_use(&mut self, path: &'v UsePath<'v>, hir_id: HirId) { - // FIXME - tracing::trace!("visiting use {:?}", path.span); - - // keep going - walk_use(self, path, hir_id); - } - fn visit_trait_item(&mut self, ti: &'v TraitItem<'v>) { - tracing::trace!("visiting trait item {:?} at {:?}", ti.ident.name, ti.span); - skip_derived_non_local!(self, ti.hir_id()); - - // match &ti.kind { - // TraitItemKind::Const(_, _) => self.no_assoc_items(ti.span), - // TraitItemKind::Type(_, _) => self.no_assoc_items(ti.span), - // TraitItemKind::Fn(bounds, ty) => (), - // } - - // keep going - walk_trait_item(self, ti); - } - fn visit_trait_item_ref(&mut self, ii: &'v TraitItemRef) { - tracing::trace!("visiting trait item ref {:?} at {:?}", ii.ident, ii.span); - walk_trait_item_ref(self, ii) - } - fn visit_impl_item(&mut self, ii: &'v ImplItem<'v>) { - tracing::trace!("visiting impl item {:?} at {:?}", ii.ident.name, ii.span,); - skip_derived_non_local!(self, ii.hir_id()); - - // tracing::trace!(" item: {:#?}", ii); - - // Check the trait for this item. - for predicate in ii.generics.predicates { - match predicate { - WherePredicate::BoundPredicate(bound) => { - for bound in bound.bounds { - match bound { - GenericBound::Trait(_poly_ref, _modifier) => { - tracing::trace!(" Skipping trait bound"); - return; - } - _ => (), - } - } - } - _ => (), - } - } - - // /// Traversing an owner node recursively to the top. - // fn traverse_owner(tcx: &TyCtxt, owner_node: OwnerNode, mut ctr: usize) { - // if ctr > 3 { - // // limit recursion. I guess I don't understand this. - // return; - // } - // ctr += 1; - // match owner_node { - // OwnerNode::Item(item) => { - // tracing::trace!(" owner is an item {:?}", item.ident); - // traverse_owner(tcx, tcx.hir().owner(item.owner_id), ctr); - // } - // OwnerNode::ForeignItem(foreign_item) => { - // tracing::trace!(" owner is a foreign item {:?}", foreign_item.ident); - // traverse_owner(tcx, tcx.hir().owner(foreign_item.owner_id), ctr); - // } - // OwnerNode::TraitItem(trait_item) => { - // tracing::trace!(" owner is an item {:?}", trait_item.ident); - // traverse_owner(tcx, tcx.hir().owner(trait_item.owner_id), ctr); - // } - // OwnerNode::ImplItem(impl_item) => { - // tracing::trace!(" owner is an item {:?}", impl_item.ident); - // traverse_owner(tcx, tcx.hir().owner(impl_item.owner_id), ctr); - // } - // OwnerNode::Crate(mot) => tracing::trace!(" owner is an item"), - // } - // } - - // Check out the owner of this impl item, i.e. we want to know the trait - // traverse_owner(self.tcx, self.tcx.hir().owner(ii.owner_id), 0); - - // match &ii.kind { - // ImplItemKind::Const(_, _) => (), // tracing::trace!("impl const {:#?}", ii.ident), - // ImplItemKind::Type(_) => tracing::trace!("impl type {:#?}", ii.ident), - // ImplItemKind::Fn(bounds, ty) => tracing::trace!("impl fn {:#?}", ii.ident), - // } - - if self.non_local_def_id(ii.owner_id.def_id.to_def_id(), ii.span) { - // Don't keep walking. - return; - } - - // keep going - walk_impl_item(self, ii); - } - fn visit_foreign_item_ref(&mut self, ii: &'v ForeignItemRef) { - tracing::trace!("visiting foreign item ref {:?} at {:?}", ii.ident, ii.span); - walk_foreign_item_ref(self, ii) - } - fn visit_impl_item_ref(&mut self, ii: &'v ImplItemRef) { - tracing::trace!("visiting impl item ref {:?} at {:?}", ii.ident, ii.span); - walk_impl_item_ref(self, ii) - } - fn visit_trait_ref(&mut self, t: &'v TraitRef<'v>) { - tracing::trace!("visiting trait ref"); - walk_trait_ref(self, t) - } - fn visit_param_bound(&mut self, bounds: &'v GenericBound<'v>) { - tracing::trace!("visiting param bound"); - walk_param_bound(self, bounds) - } - fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef<'v>) { - tracing::trace!("visiting poly trait ref {:?}", t.span); - walk_poly_trait_ref(self, t) - } - fn visit_variant_data(&mut self, s: &'v VariantData<'v>) { - tracing::trace!("visiting variant data"); - walk_struct_def(self, s) - } - fn visit_field_def(&mut self, s: &'v FieldDef<'v>) { - tracing::trace!("visiting field def {:?} at {:?}", s.ident, s.span); - walk_field_def(self, s) - } - fn visit_enum_def(&mut self, enum_definition: &'v EnumDef<'v>, item_id: HirId) { - tracing::trace!("visiting enum def"); - walk_enum_def(self, enum_definition, item_id) - } - fn visit_variant(&mut self, v: &'v Variant<'v>) { - tracing::trace!("visiting variant {:?} at {:?}", v.ident, v.span); - walk_variant(self, v) - } - fn visit_label(&mut self, label: &'v rustc_ast::ast::Label) { - tracing::trace!("visiting label {:?}", label.ident); - walk_label(self, label) - } - fn visit_infer(&mut self, inf: &'v InferArg) { - tracing::trace!("visiting infer {:?}", inf.span); - walk_inf(self, inf); - } - fn visit_generic_arg(&mut self, generic_arg: &'v GenericArg<'v>) { - tracing::trace!("visiting generic arg"); - walk_generic_arg(self, generic_arg); - } - fn visit_lifetime(&mut self, lifetime: &'v Lifetime) { - tracing::trace!("visiting lifetime {:?}", lifetime.ident); - walk_lifetime(self, lifetime) - } - // The span is that of the surrounding type/pattern/expr/whatever. - fn visit_qpath(&mut self, qpath: &'v QPath<'v>, id: HirId, span: Span) { - tracing::trace!("visiting qpath {span:?}"); - skip_derived_non_local!(self, id); - - // Look for foreign paths - match qpath { - QPath::Resolved(_ty, path) => match path.res { - _ => (), - }, - QPath::TypeRelative(_ty, _path) => (), - QPath::LangItem(item, _span, _hir_id) => { - tracing::trace!(" language item {:?}", item); - } - } - - walk_qpath(self, qpath, id) - } - fn visit_path(&mut self, path: &Path<'v>, id: HirId) { - tracing::trace!("visiting path {:?}", path.span); - - skip_derived_non_local!(self, id); - skip_v1_lib_macros!(self, id); - // tracing::trace!(" node: {:?}", self.tcx.hir().find(id)); - // tracing::trace!(" path: {:?}", path); - - match path.res { - def::Res::Def(def_kind, def_id) => { - if !def_id.is_local() { - tracing::trace!(" non local path at: {:?}", path.span); - // self.extern_crate(path.span); - } - match def_kind { - def::DefKind::Fn => tracing::trace!(" path is Fn"), - def::DefKind::Trait => tracing::trace!(" path trait"), - _ => tracing::trace!(" path is def {:?}", def_kind), - } - } - _ => (), - } - - walk_path(self, path) - } - fn visit_path_segment(&mut self, path_segment: &'v PathSegment<'v>) { - tracing::trace!("visiting path segment {:?}", path_segment.ident); - skip_derived_non_local!(self, path_segment.hir_id); - walk_path_segment(self, path_segment) - } - fn visit_generic_args(&mut self, generic_args: &'v GenericArgs<'v>) { - tracing::trace!("visiting generic args {:?}", generic_args.span_ext); - walk_generic_args(self, generic_args) - } - fn visit_assoc_type_binding(&mut self, type_binding: &'v TypeBinding<'v>) { - tracing::trace!("visiting assoc type binding {:?}", type_binding.span); - // self.no_assoc_items(type_binding.span); - - // keep going - walk_assoc_type_binding(self, type_binding); - } - fn visit_attribute(&mut self, attr: &'v rustc_ast::ast::Attribute) { - tracing::trace!("visiting attribute: {:?}", attr.span); - // match &attr.kind { - // ast::AttrKind::Normal(normal_attr) => { - // tracing::trace!("normal attribute: {:?}", normal_attr.item.path); - // } - // ast::AttrKind::DocComment(comment_kind, symbol) => (), - // } - } - fn visit_associated_item_kind(&mut self, kind: &'v AssocItemKind) { - tracing::trace!("visit assoc item kind {:?}", kind); - // self.no_assoc_items(self.span); - - // keep going - walk_associated_item_kind(self, kind); - } - fn visit_defaultness(&mut self, defaultness: &'v Defaultness) { - tracing::trace!("visiting defaultness"); - walk_defaultness(self, defaultness); - } - fn visit_inline_asm(&mut self, asm: &'v InlineAsm<'v>, _id: HirId) { - tracing::trace!("visiting inline asm"); - error::no_unsafe(self.session, asm.line_spans[0]); // XXX: what's the right span here? - - // don't keep going - // walk_inline_asm(self, asm, id); - } -} diff --git a/hax-bounded-integers/Cargo.toml b/hax-bounded-integers/Cargo.toml index 56d4f11cf..faad00ace 100644 --- a/hax-bounded-integers/Cargo.toml +++ b/hax-bounded-integers/Cargo.toml @@ -9,4 +9,6 @@ repository.workspace = true readme.workspace = true [dependencies] +duplicate = "1.0.0" hax-lib.workspace = true +paste = "1.0.15" diff --git a/hax-bounded-integers/proofs/fstar/extraction/Hax_bounded_integers.Num_traits.fst b/hax-bounded-integers/proofs/fstar/extraction/Hax_bounded_integers.Num_traits.fst index 7ca6c74e7..7cbaa7000 100644 --- a/hax-bounded-integers/proofs/fstar/extraction/Hax_bounded_integers.Num_traits.fst +++ b/hax-bounded-integers/proofs/fstar/extraction/Hax_bounded_integers.Num_traits.fst @@ -3,8 +3,8 @@ module Hax_bounded_integers.Num_traits open Core open FStar.Mul -class t_BitOps (v_Self: Type) = { - f_Output:Type; +class t_BitOps (v_Self: Type0) = { + f_Output:Type0; f_count_ones_pre:v_Self -> bool; f_count_ones_post:v_Self -> u32 -> bool; f_count_ones:x0: v_Self @@ -59,19 +59,8 @@ class t_BitOps (v_Self: Type) = { -> Prims.Pure f_Output (f_pow_pre x0 x1) (fun result -> f_pow_post x0 x1 result) } -class t_Bounded (v_Self: Type) = { - f_min_value_pre:Prims.unit -> bool; - f_min_value_post:Prims.unit -> v_Self -> bool; - f_min_value:x0: Prims.unit - -> Prims.Pure v_Self (f_min_value_pre x0) (fun result -> f_min_value_post x0 result); - f_max_value_pre:Prims.unit -> bool; - f_max_value_post:Prims.unit -> v_Self -> bool; - f_max_value:x0: Prims.unit - -> Prims.Pure v_Self (f_max_value_pre x0) (fun result -> f_max_value_post x0 result) -} - -class t_CheckedAdd (v_Self: Type) (v_Rhs: Type) = { - f_Output:Type; +class t_CheckedAdd (v_Self: Type0) (v_Rhs: Type0) = { + f_Output:Type0; f_checked_add_pre:v_Self -> v_Rhs -> bool; f_checked_add_post:v_Self -> v_Rhs -> Core.Option.t_Option f_Output -> bool; f_checked_add:x0: v_Self -> x1: v_Rhs @@ -80,8 +69,8 @@ class t_CheckedAdd (v_Self: Type) (v_Rhs: Type) = { (fun result -> f_checked_add_post x0 x1 result) } -class t_CheckedDiv (v_Self: Type) (v_Rhs: Type) = { - f_Output:Type; +class t_CheckedDiv (v_Self: Type0) (v_Rhs: Type0) = { + f_Output:Type0; f_checked_div_pre:v_Self -> v_Rhs -> bool; f_checked_div_post:v_Self -> v_Rhs -> Core.Option.t_Option f_Output -> bool; f_checked_div:x0: v_Self -> x1: v_Rhs @@ -90,8 +79,8 @@ class t_CheckedDiv (v_Self: Type) (v_Rhs: Type) = { (fun result -> f_checked_div_post x0 x1 result) } -class t_CheckedMul (v_Self: Type) (v_Rhs: Type) = { - f_Output:Type; +class t_CheckedMul (v_Self: Type0) (v_Rhs: Type0) = { + f_Output:Type0; f_checked_mul_pre:v_Self -> v_Rhs -> bool; f_checked_mul_post:v_Self -> v_Rhs -> Core.Option.t_Option f_Output -> bool; f_checked_mul:x0: v_Self -> x1: v_Rhs @@ -100,8 +89,8 @@ class t_CheckedMul (v_Self: Type) (v_Rhs: Type) = { (fun result -> f_checked_mul_post x0 x1 result) } -class t_CheckedNeg (v_Self: Type) = { - f_Output:Type; +class t_CheckedNeg (v_Self: Type0) = { + f_Output:Type0; f_checked_neg_pre:v_Self -> bool; f_checked_neg_post:v_Self -> Core.Option.t_Option f_Output -> bool; f_checked_neg:x0: v_Self @@ -110,8 +99,8 @@ class t_CheckedNeg (v_Self: Type) = { (fun result -> f_checked_neg_post x0 result) } -class t_CheckedSub (v_Self: Type) (v_Rhs: Type) = { - f_Output:Type; +class t_CheckedSub (v_Self: Type0) (v_Rhs: Type0) = { + f_Output:Type0; f_checked_sub_pre:v_Self -> v_Rhs -> bool; f_checked_sub_post:v_Self -> v_Rhs -> Core.Option.t_Option f_Output -> bool; f_checked_sub:x0: v_Self -> x1: v_Rhs @@ -120,8 +109,8 @@ class t_CheckedSub (v_Self: Type) (v_Rhs: Type) = { (fun result -> f_checked_sub_post x0 x1 result) } -class t_FromBytes (v_Self: Type) = { - f_BYTES:Type; +class t_FromBytes (v_Self: Type0) = { + f_BYTES:Type0; f_from_le_bytes_pre:f_BYTES -> bool; f_from_le_bytes_post:f_BYTES -> v_Self -> bool; f_from_le_bytes:x0: f_BYTES @@ -132,43 +121,43 @@ class t_FromBytes (v_Self: Type) = { -> Prims.Pure v_Self (f_from_be_bytes_pre x0) (fun result -> f_from_be_bytes_post x0 result) } -class t_NumOps (v_Self: Type) (v_Rhs: Type) (v_Output: Type) = { - [@@@ FStar.Tactics.Typeclasses.no_method]_super_3420555054487092457:Core.Ops.Arith.t_Add v_Self +class t_NumOps (v_Self: Type0) (v_Rhs: Type0) (v_Output: Type0) = { + [@@@ FStar.Tactics.Typeclasses.no_method]_super_9126539072073536218:Core.Ops.Arith.t_Add v_Self v_Rhs; - [@@@ FStar.Tactics.Typeclasses.no_method]_super_16858356355397389837:Core.Ops.Arith.t_Sub v_Self + [@@@ FStar.Tactics.Typeclasses.no_method]_super_9784678892199232396:Core.Ops.Arith.t_Sub v_Self v_Rhs; - [@@@ FStar.Tactics.Typeclasses.no_method]_super_3009625865770964073:Core.Ops.Arith.t_Mul v_Self + [@@@ FStar.Tactics.Typeclasses.no_method]_super_7005199110250618039:Core.Ops.Arith.t_Mul v_Self v_Rhs; - [@@@ FStar.Tactics.Typeclasses.no_method]_super_9111207129981210576:Core.Ops.Arith.t_Div v_Self + [@@@ FStar.Tactics.Typeclasses.no_method]_super_12366019628759357413:Core.Ops.Arith.t_Div v_Self v_Rhs; - [@@@ FStar.Tactics.Typeclasses.no_method]_super_16804214316696687705:Core.Ops.Arith.t_Rem v_Self + [@@@ FStar.Tactics.Typeclasses.no_method]_super_11859756759858186302:Core.Ops.Arith.t_Rem v_Self v_Rhs } -class t_One (v_Self: Type) = { +class t_One (v_Self: Type0) = { f_one_pre:Prims.unit -> bool; f_one_post:Prims.unit -> v_Self -> bool; f_one:x0: Prims.unit -> Prims.Pure v_Self (f_one_pre x0) (fun result -> f_one_post x0 result) } -class t_ToBytes (v_Self: Type) = { - [@@@ FStar.Tactics.Typeclasses.no_method]_super_4530633244223603628:t_FromBytes v_Self; +class t_ToBytes (v_Self: Type0) = { + [@@@ FStar.Tactics.Typeclasses.no_method]_super_3732703090464998751:t_FromBytes v_Self; f_to_le_bytes_pre:v_Self -> bool; - f_to_le_bytes_post:v_Self -> v_4530633244223603628.f_BYTES -> bool; + f_to_le_bytes_post:v_Self -> v_3732703090464998751.f_BYTES -> bool; f_to_le_bytes:x0: v_Self - -> Prims.Pure v_4530633244223603628.f_BYTES + -> Prims.Pure v_3732703090464998751.f_BYTES (f_to_le_bytes_pre x0) (fun result -> f_to_le_bytes_post x0 result); f_to_be_bytes_pre:v_Self -> bool; - f_to_be_bytes_post:v_Self -> v_4530633244223603628.f_BYTES -> bool; + f_to_be_bytes_post:v_Self -> v_3732703090464998751.f_BYTES -> bool; f_to_be_bytes:x0: v_Self - -> Prims.Pure v_4530633244223603628.f_BYTES + -> Prims.Pure v_3732703090464998751.f_BYTES (f_to_be_bytes_pre x0) (fun result -> f_to_be_bytes_post x0 result) } -class t_WrappingAdd (v_Self: Type) (v_Rhs: Type) = { - f_Output:Type; +class t_WrappingAdd (v_Self: Type0) (v_Rhs: Type0) = { + f_Output:Type0; f_wrapping_add_pre:v_Self -> v_Rhs -> bool; f_wrapping_add_post:v_Self -> v_Rhs -> f_Output -> bool; f_wrapping_add:x0: v_Self -> x1: v_Rhs @@ -177,8 +166,8 @@ class t_WrappingAdd (v_Self: Type) (v_Rhs: Type) = { (fun result -> f_wrapping_add_post x0 x1 result) } -class t_WrappingDiv (v_Self: Type) (v_Rhs: Type) = { - f_Output:Type; +class t_WrappingDiv (v_Self: Type0) (v_Rhs: Type0) = { + f_Output:Type0; f_wrapping_div_pre:v_Self -> v_Rhs -> bool; f_wrapping_div_post:v_Self -> v_Rhs -> f_Output -> bool; f_wrapping_div:x0: v_Self -> x1: v_Rhs @@ -187,8 +176,8 @@ class t_WrappingDiv (v_Self: Type) (v_Rhs: Type) = { (fun result -> f_wrapping_div_post x0 x1 result) } -class t_WrappingMul (v_Self: Type) (v_Rhs: Type) = { - f_Output:Type; +class t_WrappingMul (v_Self: Type0) (v_Rhs: Type0) = { + f_Output:Type0; f_wrapping_mul_pre:v_Self -> v_Rhs -> bool; f_wrapping_mul_post:v_Self -> v_Rhs -> f_Output -> bool; f_wrapping_mul:x0: v_Self -> x1: v_Rhs @@ -197,8 +186,8 @@ class t_WrappingMul (v_Self: Type) (v_Rhs: Type) = { (fun result -> f_wrapping_mul_post x0 x1 result) } -class t_WrappingSub (v_Self: Type) (v_Rhs: Type) = { - f_Output:Type; +class t_WrappingSub (v_Self: Type0) (v_Rhs: Type0) = { + f_Output:Type0; f_wrapping_sub_pre:v_Self -> v_Rhs -> bool; f_wrapping_sub_post:v_Self -> v_Rhs -> f_Output -> bool; f_wrapping_sub:x0: v_Self -> x1: v_Rhs @@ -207,44 +196,43 @@ class t_WrappingSub (v_Self: Type) (v_Rhs: Type) = { (fun result -> f_wrapping_sub_post x0 x1 result) } -class t_Zero (v_Self: Type) = { +class t_Zero (v_Self: Type0) = { f_zero_pre:Prims.unit -> bool; f_zero_post:Prims.unit -> v_Self -> bool; f_zero:x0: Prims.unit -> Prims.Pure v_Self (f_zero_pre x0) (fun result -> f_zero_post x0 result) } -class t_MachineInt (v_Self: Type) (v_Output: Type) = { - [@@@ FStar.Tactics.Typeclasses.no_method]_super_957087622381469234:Core.Marker.t_Copy v_Self; - [@@@ FStar.Tactics.Typeclasses.no_method]_super_7243498280507755391:t_Bounded v_Self; - [@@@ FStar.Tactics.Typeclasses.no_method]_super_9802961870013064174:Core.Cmp.t_PartialOrd v_Self +class t_MachineInt (v_Self: Type0) (v_Output: Type0) = { + [@@@ FStar.Tactics.Typeclasses.no_method]_super_11581440318597584651:Core.Marker.t_Copy v_Self; + [@@@ FStar.Tactics.Typeclasses.no_method]_super_12866954522599331834:Core.Cmp.t_PartialOrd v_Self v_Self; - [@@@ FStar.Tactics.Typeclasses.no_method]_super_15372362079243870652:Core.Cmp.t_Ord v_Self; - [@@@ FStar.Tactics.Typeclasses.no_method]_super_1959006841676202949:Core.Cmp.t_PartialEq v_Self + [@@@ FStar.Tactics.Typeclasses.no_method]_super_13035911912416111195:Core.Cmp.t_Ord v_Self; + [@@@ FStar.Tactics.Typeclasses.no_method]_super_12632649257025169145:Core.Cmp.t_PartialEq v_Self v_Self; - [@@@ FStar.Tactics.Typeclasses.no_method]_super_8995075768394296398:Core.Cmp.t_Eq v_Self; - [@@@ FStar.Tactics.Typeclasses.no_method]_super_2630392019625310516:t_Zero v_Self; - [@@@ FStar.Tactics.Typeclasses.no_method]_super_6913784476497246329:t_One v_Self; - [@@@ FStar.Tactics.Typeclasses.no_method]_super_9936546819275964215:Core.Ops.Bit.t_Not v_Self; - [@@@ FStar.Tactics.Typeclasses.no_method]_super_1531387235085686842:t_NumOps v_Self + [@@@ FStar.Tactics.Typeclasses.no_method]_super_8099741844003281729:Core.Cmp.t_Eq v_Self; + [@@@ FStar.Tactics.Typeclasses.no_method]_super_9841570312332416173:t_Zero v_Self; + [@@@ FStar.Tactics.Typeclasses.no_method]_super_12668241202577409386:t_One v_Self; + [@@@ FStar.Tactics.Typeclasses.no_method]_super_9487321769118300762:Core.Ops.Bit.t_Not v_Self; + [@@@ FStar.Tactics.Typeclasses.no_method]_super_1980884762883925305:t_NumOps v_Self v_Self v_Output; - [@@@ FStar.Tactics.Typeclasses.no_method]_super_3786882699227749486:Core.Ops.Bit.t_BitAnd v_Self + [@@@ FStar.Tactics.Typeclasses.no_method]_super_13929479875548649875:Core.Ops.Bit.t_BitAnd v_Self v_Self; - [@@@ FStar.Tactics.Typeclasses.no_method]_super_8095144530696857283:Core.Ops.Bit.t_BitOr v_Self + [@@@ FStar.Tactics.Typeclasses.no_method]_super_1708325062211865233:Core.Ops.Bit.t_BitOr v_Self v_Self; - [@@@ FStar.Tactics.Typeclasses.no_method]_super_15313863003467220491:Core.Ops.Bit.t_BitXor v_Self + [@@@ FStar.Tactics.Typeclasses.no_method]_super_1501688608269502122:Core.Ops.Bit.t_BitXor v_Self v_Self; - [@@@ FStar.Tactics.Typeclasses.no_method]_super_13306778606414288955:Core.Ops.Bit.t_Shl v_Self + [@@@ FStar.Tactics.Typeclasses.no_method]_super_15083490293093561556:Core.Ops.Bit.t_Shl v_Self v_Self; - [@@@ FStar.Tactics.Typeclasses.no_method]_super_2333720355461387358:Core.Ops.Bit.t_Shr v_Self + [@@@ FStar.Tactics.Typeclasses.no_method]_super_9065931548762825726:Core.Ops.Bit.t_Shr v_Self v_Self; - [@@@ FStar.Tactics.Typeclasses.no_method]_super_10133521522977299931:t_CheckedAdd v_Self v_Self; - [@@@ FStar.Tactics.Typeclasses.no_method]_super_16509367665728242671:t_CheckedSub v_Self v_Self; - [@@@ FStar.Tactics.Typeclasses.no_method]_super_261087305577220356:t_CheckedMul v_Self v_Self; - [@@@ FStar.Tactics.Typeclasses.no_method]_super_4808020806666262858:t_CheckedDiv v_Self v_Self; - [@@@ FStar.Tactics.Typeclasses.no_method]_super_18005178388944789845:t_WrappingAdd v_Self v_Self; - [@@@ FStar.Tactics.Typeclasses.no_method]_super_11471591230230619611:t_WrappingSub v_Self v_Self; - [@@@ FStar.Tactics.Typeclasses.no_method]_super_5940229659009370734:t_WrappingMul v_Self v_Self; - [@@@ FStar.Tactics.Typeclasses.no_method]_super_1640938766960073185:t_WrappingDiv v_Self v_Self; - [@@@ FStar.Tactics.Typeclasses.no_method]_super_12477248635475532096:t_BitOps v_Self + [@@@ FStar.Tactics.Typeclasses.no_method]_super_5052970308637232515:t_CheckedAdd v_Self v_Self; + [@@@ FStar.Tactics.Typeclasses.no_method]_super_739902999637339236:t_CheckedSub v_Self v_Self; + [@@@ FStar.Tactics.Typeclasses.no_method]_super_15323401662629887609:t_CheckedMul v_Self v_Self; + [@@@ FStar.Tactics.Typeclasses.no_method]_super_8119502507145032897:t_CheckedDiv v_Self v_Self; + [@@@ FStar.Tactics.Typeclasses.no_method]_super_12846047806852469117:t_WrappingAdd v_Self v_Self; + [@@@ FStar.Tactics.Typeclasses.no_method]_super_12408554086330550784:t_WrappingSub v_Self v_Self; + [@@@ FStar.Tactics.Typeclasses.no_method]_super_8633193508996485932:t_WrappingMul v_Self v_Self; + [@@@ FStar.Tactics.Typeclasses.no_method]_super_16339457892016115661:t_WrappingDiv v_Self v_Self; + [@@@ FStar.Tactics.Typeclasses.no_method]_super_12348120774285878195:t_BitOps v_Self } diff --git a/hax-bounded-integers/proofs/fstar/extraction/Hax_bounded_integers.fst b/hax-bounded-integers/proofs/fstar/extraction/Hax_bounded_integers.fst index 8bf53bddf..91f2bdcf6 100644 --- a/hax-bounded-integers/proofs/fstar/extraction/Hax_bounded_integers.fst +++ b/hax-bounded-integers/proofs/fstar/extraction/Hax_bounded_integers.fst @@ -37,4 +37,4 @@ let t_BoundedU64 (v_MIN v_MAX: u64) = x: u64{x >=. v_MIN && x <=. v_MAX} let t_BoundedU8 (v_MIN v_MAX: u8) = x: u8{x >=. v_MIN && x <=. v_MAX} ///Bounded usize integers. This struct enforces the invariant that values are greater or equal to `MIN` and less or equal to `MAX`. -unfold let t_BoundedUsize (v_MIN v_MAX: usize) = x: usize{x >=. v_MIN && x <=. v_MAX} +let t_BoundedUsize (v_MIN v_MAX: usize) = x: usize{x >=. v_MIN && x <=. v_MAX} diff --git a/hax-bounded-integers/src/lib.rs b/hax-bounded-integers/src/lib.rs index 1f9bbd07e..753e8ea2a 100644 --- a/hax-bounded-integers/src/lib.rs +++ b/hax-bounded-integers/src/lib.rs @@ -1,60 +1,147 @@ use hax_lib::Refinement; pub mod num_traits; +#[doc(hidden)] +#[macro_export] macro_rules! derivate_binop_for_bounded { - ({$t:ident, $bounded_t:ident}; $($tt:tt)*) => { - derivate_binop_for_bounded!({$t, $bounded_t, get, Self::Output}; $($tt)*) ; + ($(<$(const $cst_name:ident : $cst_ty:ty),*>)?{$t:ident, $bounded_t:ident}; $($tt:tt)*) => { + $crate::derivate_binop_for_bounded!($(<$(const $cst_name:$cst_ty),*>)?{$t, $bounded_t, get, Self::Output}; $($tt)*) ; }; - ({$t:ident, $bounded_t:ident, $get:ident, $out:ty};) => {}; - ({$t:ident, $bounded_t:ident, $get:ident, $out:ty}; ($trait:ident, $meth:ident), $($tt:tt)*) => { - derivate_binop_for_bounded!(@$t, $bounded_t, $trait, $meth, $get, $out); - derivate_binop_for_bounded!({$t, $bounded_t, $get, $out}; $($tt)*); + ($(<$(const $cst_name:ident : $cst_ty:ty),*>)?{$t:ident, $bounded_t:ident, $get:ident, $out:ty};) => {}; + ($(<$(const $cst_name:ident : $cst_ty:ty),*>)?{$t:ident, $bounded_t:ident, $get:ident, $out:ty}; ($trait:ident, $meth:ident), $($tt:tt)*) => { + $crate::derivate_binop_for_bounded!(@$t, $bounded_t, $trait, $meth, $get, $out, $(<$(const $cst_name:$cst_ty),*>)?); + $crate::derivate_binop_for_bounded!($(<$(const $cst_name:$cst_ty),*>)?{$t, $bounded_t, $get, $out}; $($tt)*); }; - (@$t:ident, $bounded_t:ident, $trait:ident, $meth:ident, $get:ident, $out:ty) => { - // BoundedT BoundedT - impl - $trait<$bounded_t> for $bounded_t - { - type Output = $t; - #[inline(always)] - fn $meth(self, other: $bounded_t) -> $out { - (self.$get()).$meth(other.$get()) + (@$t:ident, $bounded_t:ident, $trait:ident, $meth:ident, $get:ident, $out:ty$(,)?) => { + $crate::derivate_binop_for_bounded!( + @$t, $bounded_t, $trait, $meth, $get, $out, + + ); + }; + (@$t:ident, $bounded_t:ident, $trait:ident, $meth:ident, $get:ident, $out:ty, + <$(const $cst_name:ident : $cst_ty:ty),*> + ) => { + paste::paste!{ + // BoundedT BoundedT + impl<$(const [< $cst_name _LHS >]: $cst_ty,)* $(const [< $cst_name _RHS >]: $cst_ty,)*> + $trait<$bounded_t<$([< $cst_name _RHS >],)*>> for $bounded_t<$([< $cst_name _LHS >],)*> + { + type Output = $t; + #[inline(always)] + fn $meth(self, other: $bounded_t<$([< $cst_name _RHS >],)*>) -> $out { + (self.$get()).$meth(other.$get()) + } } - } - // BoundedT T - impl $trait<$t> for $bounded_t { - type Output = $t; - #[inline(always)] - fn $meth(self, other: $t) -> $out { - (self.$get()).$meth(other) + // BoundedT T + impl<$(const $cst_name: $cst_ty,)*> $trait<$t> for $bounded_t<$($cst_name,)*> { + type Output = $t; + #[inline(always)] + fn $meth(self, other: $t) -> $out { + (self.$get()).$meth(other) + } } - } - // T BoundedT - impl $trait<$bounded_t> for $t { - type Output = $t; - #[inline(always)] - fn $meth(self, other: $bounded_t) -> $out { - (self).$meth(other.$get()) + + // T BoundedT + impl<$(const $cst_name: $cst_ty,)*> $trait<$bounded_t<$($cst_name,)*>> for $t { + type Output = $t; + #[inline(always)] + fn $meth(self, other: $bounded_t<$($cst_name,)*>) -> $out { + (self).$meth(other.$get()) + } } } }; } -macro_rules! mk_bounded { - ($bounded_t:ident($t: ident $($bytes:expr)?)$(,)?) => { - #[doc = concat!("Bounded ", stringify!($t)," integers. This struct enforces the invariant that values are greater or equal to `MIN` and less or equal to `MAX`.")] - #[hax_lib::refinement_type(|x| x >= MIN && x <= MAX)] - #[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] - pub struct $bounded_t($t); +#[doc(hidden)] +#[macro_export] +macro_rules! derivate_assign_binop_for_bounded { + ($(<$(const $cst_name:ident : $cst_ty:ty),*>)?{$t:ident, $bounded_t:ident}; $($tt:tt)*) => { + $crate::derivate_assign_binop_for_bounded!($(<$(const $cst_name:$cst_ty),*>)?{$t, $bounded_t, get, Self::Output}; $($tt)*) ; + }; + ($(<$(const $cst_name:ident : $cst_ty:ty),*>)?{$t:ident, $bounded_t:ident, $get:ident, $out:ty};) => {}; + ($(<$(const $cst_name:ident : $cst_ty:ty),*>)?{$t:ident, $bounded_t:ident, $get:ident, $out:ty}; ($trait:ident, $meth:ident), $($tt:tt)*) => { + $crate::derivate_assign_binop_for_bounded!(@$t, $bounded_t, $trait, $meth, $get, $out, $(<$(const $cst_name:$cst_ty),*>)?); + $crate::derivate_assign_binop_for_bounded!($(<$(const $cst_name:$cst_ty),*>)?{$t, $bounded_t, $get, $out}; $($tt)*); + }; + (@$t:ident, $bounded_t:ident, $trait:ident, $meth:ident, $get:ident, $out:ty$(,)?) => { + $crate::derivate_assign_binop_for_bounded!( + @$t, $bounded_t, $trait, $meth, $get, $out, + + ); + }; + (@$t:ident, $bounded_t:ident, $trait:ident, $meth:ident, $get:ident, $out:ty, + <$(const $cst_name:ident : $cst_ty:ty),*> + ) => { + paste::paste!{ + // BoundedT BoundedT + impl<$(const [< $cst_name _LHS >]: $cst_ty,)* $(const [< $cst_name _RHS >]: $cst_ty,)*> + $trait<$bounded_t<$([< $cst_name _RHS >],)*>> for $bounded_t<$([< $cst_name _LHS >],)*> + { + #[inline(always)] + fn $meth(&mut self, other: $bounded_t<$([< $cst_name _RHS >],)*>) { + self.get_mut().$meth(other.$get()) + } + } - #[hax_lib::exclude] + // BoundedT $t + impl<$(const [< $cst_name _LHS >]: $cst_ty,)*> + $trait<$t> for $bounded_t<$([< $cst_name _LHS >],)*> + { + #[inline(always)] + fn $meth(&mut self, other: $t) { + self.get_mut().$meth(other) + } + } + + // $t BoundedT + impl<$(const [< $cst_name _RHS >]: $cst_ty,)*> + $trait<$bounded_t<$([< $cst_name _RHS >],)*>> for $t + { + #[inline(always)] + fn $meth(&mut self, other: $bounded_t<$([< $cst_name _RHS >],)*>) { + self.$meth(other.get()) + } + } + } + }; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! derivate_operations_for_bounded { + ($bounded_t:ident($t: ident $($bytes:expr)?)$(,)? + <$(const $cst_name:ident : $cst_ty:ty),*> + ) => { + #[duplicate::duplicate_item( + INTRO_CONSTANTS USE_CONSTANTS; + [ $(const $cst_name:$cst_ty),* ] [ $($cst_name),* ]; + )] + #[hax_lib::exclude] const _: () = { - use core::ops::*; - use num_traits::*; + use ::core::ops::*; + use $crate::num_traits::*; + use ::hax_lib::Refinement; + + $crate::derivate_assign_binop_for_bounded!( + + {$t, $bounded_t}; + (AddAssign, add_assign), + (SubAssign, sub_assign), + (MulAssign, mul_assign), + (DivAssign, div_assign), + (RemAssign, rem_assign), + (ShlAssign, shl_assign), + (ShrAssign, shr_assign), + (BitAndAssign, bitand_assign), + (BitOrAssign, bitor_assign), + (BitXorAssign, bitxor_assign), + ); - derivate_binop_for_bounded!( + $crate::derivate_binop_for_bounded!( + {$t, $bounded_t}; (Add, add), (Sub, sub), (Mul, mul), (Div, div), (Rem, rem), (BitOr, bitor), (BitAnd, bitand), (BitXor, bitxor), @@ -63,13 +150,14 @@ macro_rules! mk_bounded { (WrappingMul, wrapping_mul), (WrappingDiv, wrapping_div), ); - derivate_binop_for_bounded!( + $crate::derivate_binop_for_bounded!( + {$t, $bounded_t, get, Option}; (CheckedAdd, checked_add), (CheckedSub, checked_sub), (CheckedMul, checked_mul), (CheckedDiv, checked_div), ); - impl CheckedNeg for $bounded_t { + impl CheckedNeg for $bounded_t { type Output = $t; #[inline(always)] fn checked_neg(&self) -> Option<$t> { @@ -77,7 +165,7 @@ macro_rules! mk_bounded { } } - impl Not for $bounded_t { + impl Not for $bounded_t { type Output = $t; #[inline(always)] fn not(self) -> Self::Output { @@ -85,21 +173,21 @@ macro_rules! mk_bounded { } } - impl NumOps for $bounded_t {} + impl NumOps for $bounded_t {} - impl Bounded for $bounded_t { - #[inline(always)] - fn min_value() -> Self { - Self::new(MIN) - } - #[inline(always)] - fn max_value() -> Self { - Self::new(MAX) - } - } + // impl Bounded for $bounded_t { + // #[inline(always)] + // fn min_value() -> Self { + // Self::new(MIN) + // } + // #[inline(always)] + // fn max_value() -> Self { + // Self::new(MAX) + // } + // } $( - impl FromBytes for $bounded_t { + impl FromBytes for $bounded_t { type BYTES = [u8; $bytes]; #[inline(always)] @@ -112,7 +200,7 @@ macro_rules! mk_bounded { } } - impl ToBytes for $bounded_t { + impl ToBytes for $bounded_t { #[inline(always)] fn to_le_bytes(self) -> Self::BYTES { self.get().to_le_bytes() @@ -124,23 +212,23 @@ macro_rules! mk_bounded { } )? - impl Zero for $bounded_t { + impl Zero for $bounded_t { #[inline(always)] fn zero() -> Self { - Self::new(1) + Self::new(0) } } - impl One for $bounded_t { + impl One for $bounded_t { #[inline(always)] fn one() -> Self { - Self::new(0) + Self::new(1) } } - impl MachineInt<$t> for $bounded_t { } + impl MachineInt<$t> for $bounded_t { } - impl BitOps for $bounded_t { + impl BitOps for $bounded_t { type Output = $t; #[inline(always)] @@ -197,10 +285,28 @@ macro_rules! mk_bounded { } } }; + } +} + +#[doc(hidden)] +#[macro_export] +macro_rules! mk_bounded { + ($(#$attr:tt)* $bounded_t:ident<$(const $cst_name:ident : $cst_ty:ty),*>($t: ident $($bytes:expr)?, |$x:ident| $body:expr)$(,)?) => { + #[hax_lib::refinement_type(|$x| $body)] + #[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] + $(#$attr)* + pub struct $bounded_t<$(const $cst_name : $cst_ty),*>($t); + $crate::derivate_operations_for_bounded!($bounded_t($t$($bytes)?)<$(const $cst_name : $cst_ty),*>); + }; + ($bounded_t:ident($t: ident $($bytes:expr)?)$(,)?) => { + $crate::mk_bounded!( + #[doc = concat!("Bounded ", stringify!($t)," integers. This struct enforces the invariant that values are greater or equal to `MIN` and less or equal to `MAX`.")] + $bounded_t($t $($bytes)?, |x| x >= MIN && x <= MAX) + ); }; ($bounded_t:ident($t: ident $($bytes:expr)?), $($tt:tt)+) => { - mk_bounded!($bounded_t($t $($bytes)?)); - mk_bounded!($($tt)+); + $crate::mk_bounded!($bounded_t($t $($bytes)?)); + $crate::mk_bounded!($($tt)+); }; } @@ -219,6 +325,23 @@ mk_bounded!( BoundedUsize(usize), ); +/// Makes a refined new type in a very similar way to +/// `hax_lib::refinement_tyoe`, but derives the various traits an +/// integer type is expected to implement. +/// +/// Examples: +/// ```rust +/// # use hax_bounded_integers::refinement_int; +/// refinement_int!(BoundedAbsI16(i16, 2, |x| x >= -(B as i16) && x <= (B as i16))); +/// refinement_int!(BoundedAbsIsize(isize, |x| x >= -(B as isize) && x <= (B as isize))); +/// ``` +#[macro_export] +macro_rules! refinement_int { + ($(#$attr:tt)* $bounded_t:ident$(<$(const $cst_name:ident : $cst_ty:ty),*$(,)?>)?($t: ident, $($bytes:literal,)? |$x:ident| $body:expr)$(,)?) => { + $crate::mk_bounded!($(#$attr)* $bounded_t<$($(const $cst_name:$cst_ty),*)?>($t $($bytes)?, |$x| $body)); + }; +} + #[hax_lib::exclude] const _: () = { impl core::ops::Index> for [T] { @@ -239,8 +362,15 @@ const _: () = { #[test] fn tests() { + refinement_int!( + Test(i16, 2, |x| B < 32768 && x >= -(B as i16) && x <= (B as i16)) + ); + use hax_lib::*; + let mut zzz: Test<123> = (-122).into_checked(); + zzz += 32; + let x: BoundedU8<0, 5> = 2.into_checked(); let y: BoundedU8<5, 10> = (x + x).into_checked(); diff --git a/hax-bounded-integers/src/num_traits.rs b/hax-bounded-integers/src/num_traits.rs index c34a710e8..ec3b06c99 100644 --- a/hax-bounded-integers/src/num_traits.rs +++ b/hax-bounded-integers/src/num_traits.rs @@ -31,10 +31,10 @@ pub trait NumOps: { } -pub trait Bounded { - fn min_value() -> Self; - fn max_value() -> Self; -} +// pub trait Bounded { +// fn min_value() -> Self; +// fn max_value() -> Self; +// } pub trait WrappingAdd { type Output; @@ -95,7 +95,7 @@ pub trait ToBytes: FromBytes { pub trait MachineInt: Copy - + Bounded + // + Bounded + PartialOrd + Ord + PartialEq diff --git a/hax-lib-macros/Cargo.toml b/hax-lib-macros/Cargo.toml index a2f4a5af4..90350bf24 100644 --- a/hax-lib-macros/Cargo.toml +++ b/hax-lib-macros/Cargo.toml @@ -19,10 +19,12 @@ quote.workspace = true syn = { version = "2.0", features = [ "full", "visit-mut", + "visit", "extra-traits", "parsing", ] } hax-lib-macros-types.workspace = true +paste = "1.0.15" [dev-dependencies] hax-lib = { path = "../hax-lib" } diff --git a/hax-lib-macros/src/impl_fn_decoration.rs b/hax-lib-macros/src/impl_fn_decoration.rs new file mode 100644 index 000000000..da39b500c --- /dev/null +++ b/hax-lib-macros/src/impl_fn_decoration.rs @@ -0,0 +1,87 @@ +//! This module defines the `ImplFnDecoration` structure and utils +//! around it. + +use crate::prelude::*; +use crate::utils::*; + +/// Supporting structure that holds the data required by the internal +/// macro `impl_fn_decoration`. +pub struct ImplFnDecoration { + pub kind: FnDecorationKind, + pub phi: Expr, + pub generics: Generics, + pub self_ty: Type, +} + +/// The various strings allowed as decoration kinds. +pub const DECORATION_KINDS: &[&str] = &["decreases", "ensures", "requires"]; + +/// Expects a `Path` to be a decoration kind: `::hax_lib::`, +/// `hax_lib::` or `` in (with `KIND` in +/// `DECORATION_KINDS`). +pub fn expects_path_decoration(path: &Path) -> Result> { + let path_span = path.span(); + let path = path + .expect_simple_path() + .ok_or_else(|| Error::new(path_span, "Expected a simple path, with no `<...>`."))?; + Ok( + match path + .iter() + .map(|x| x.as_str()) + .collect::>() + .as_slice() + { + [kw] | ["", "hax_lib", kw] | ["hax_lib", kw] if DECORATION_KINDS.contains(kw) => { + Some(kw.to_string()) + } + _ => None, + }, + ) +} + +impl parse::Parse for ImplFnDecoration { + fn parse(input: parse::ParseStream) -> Result { + let parse_next = || -> Result<_> { + input.parse::()?; + let mut generics = input.parse::()?; + input.parse::()?; + generics.where_clause = input.parse::>()?; + input.parse::()?; + let self_ty = input.parse::()?; + input.parse::()?; + Ok((generics, self_ty)) + }; + + let path = input.parse::()?; + let path_span = path.span(); + let kind = match expects_path_decoration(&path)? { + Some(s) => match s.as_str() { + "decreases" => FnDecorationKind::Decreases, + "requires" => FnDecorationKind::Requires, + "ensures" => { + let (generics, self_ty) = parse_next()?; + let ExprClosure1 { arg, body } = input.parse::()?; + input.parse::()?; + return Ok(ImplFnDecoration { + kind: FnDecorationKind::Ensures { ret_binder: arg }, + phi: body, + generics, + self_ty, + }); + } + _ => unreachable!(), + } + None => Err(Error::new(path_span, "Expected `::hax_lib::`, `hax_lib::` or `` with `KIND` in {DECORATION_KINDS:?}"))?, + }; + + let (generics, self_ty) = parse_next()?; + let phi = input.parse::()?; + input.parse::()?; + Ok(ImplFnDecoration { + kind, + phi, + generics, + self_ty, + }) + } +} diff --git a/hax-lib-macros/src/lib.rs b/hax-lib-macros/src/lib.rs index 5edbd8201..22261bf84 100644 --- a/hax-lib-macros/src/lib.rs +++ b/hax-lib-macros/src/lib.rs @@ -1,13 +1,16 @@ +mod impl_fn_decoration; mod quote; mod rewrite_self; mod syn_ext; mod utils; mod prelude { + pub use crate::syn_ext::*; pub use proc_macro as pm; pub use proc_macro2::*; pub use proc_macro_error::*; pub use quote::*; + pub use std::collections::HashSet; pub use syn::spanned::Spanned; pub use syn::{visit_mut::VisitMut, *}; @@ -16,10 +19,110 @@ mod prelude { pub type FnLike = syn::ImplItemFn; } +use impl_fn_decoration::*; use prelude::*; -use syn_ext::*; use utils::*; +/// When extracting to F*, wrap this item in `#push-options "..."` and +/// `#pop-options`. +#[proc_macro_error] +#[proc_macro_attribute] +pub fn fstar_options(attr: pm::TokenStream, item: pm::TokenStream) -> pm::TokenStream { + let item: TokenStream = item.into(); + let lit_str = parse_macro_input!(attr as LitStr); + let payload = format!(r#"#push-options "{}""#, lit_str.value()); + let payload = LitStr::new(&payload, lit_str.span()); + quote! { + #[::hax_lib::fstar::before(#payload)] + #[::hax_lib::fstar::after(r#"#pop-options"#)] + #item + } + .into() +} + +/// Add an invariant to a loop which deals with an index. The +/// invariant cannot refer to any variable introduced within the +/// loop. An invariant is a closure that takes one argument, the +/// index, and returns a boolean. +/// +/// Note that loop invariants are unstable (this will be handled in a +/// better way in the future, see +/// https://github.com/hacspec/hax/issues/858) and only supported on +/// specific `for` loops with specific iterators: +/// +/// - `for i in start..end {...}` +/// - `for i in (start..end).step_by(n) {...}` +/// - `for i in slice.enumerate() {...}` +/// - `for i in slice.chunks_exact(n).enumerate() {...}` +/// +/// This function must be called on the first line of a loop body to +/// be effective. Note that in the invariant expression, `forall`, +/// `exists`, and `BACKEND!` (`BACKEND` can be `fstar`, `proverif`, +/// `coq`...) are in scope. +#[proc_macro] +pub fn loop_invariant(predicate: pm::TokenStream) -> pm::TokenStream { + let predicate: TokenStream = predicate.into(); + let ts: pm::TokenStream = quote! { + #[cfg(#HaxCfgOptionName)] + { + hax_lib::_internal_loop_invariant({ + #HaxQuantifiers + #predicate + }) + } + } + .into(); + ts +} + +/// When extracting to F*, inform about what is the current +/// verification status for an item. It can either be `lax` or +/// `panic_free`. +#[proc_macro_error] +#[proc_macro_attribute] +pub fn fstar_verification_status(attr: pm::TokenStream, item: pm::TokenStream) -> pm::TokenStream { + let action = format!("{}", parse_macro_input!(attr as Ident)); + match action.as_str() { + "lax" => { + let item: TokenStream = item.into(); + quote! { + #[::hax_lib::fstar::options("--admit_smt_queries true")] + #item + } + } + "panic_free" => { + let mut item = parse_macro_input!(item as FnLike); + if let Some(last) = item + .block + .stmts + .iter_mut() + .rev() + .find(|stmt| matches!(stmt, syn::Stmt::Expr(_, None))) + .as_mut() + { + **last = syn::Stmt::Expr( + parse_quote! { + {let result = #last; + ::hax_lib::fstar!("_hax_panic_freedom_admit_"); + result} + }, + None, + ); + } else { + item.block.stmts.push(syn::Stmt::Expr( + parse_quote! {::hax_lib::fstar!("_hax_panic_freedom_admit_")}, + None, + )); + } + quote! { + #item + } + } + _ => abort_call_site!(format!("Expected `lax` or `panic_free`")), + } + .into() +} + /// Include this item in the Hax translation. #[proc_macro_error] #[proc_macro_attribute] @@ -188,6 +291,13 @@ pub fn decreases(attr: pm::TokenStream, item: pm::TokenStream) -> pm::TokenStrea /// Add a logical precondition to a function. // Note you can use the `forall` and `exists` operators. (TODO: commented out for now, see #297) +/// In the case of a function that has one or more `&mut` inputs, in +/// the `ensures` clause, you can refer to such an `&mut` input `x` as +/// `x` for its "past" value and `future(x)` for its "future" value. +/// +/// You can use the (unqualified) macro `fstar!` (`BACKEND!` for any +/// backend `BACKEND`) to inline F* (or Coq, ProVerif, etc.) code in +/// the precondition, e.g. `fstar!("true")`. /// /// # Example /// @@ -233,6 +343,10 @@ pub fn requires(attr: pm::TokenStream, item: pm::TokenStream) -> pm::TokenStream /// Add a logical postcondition to a function. Note you can use the /// `forall` and `exists` operators. /// +/// You can use the (unqualified) macro `fstar!` (`BACKEND!` for any +/// backend `BACKEND`) to inline F* (or Coq, ProVerif, etc.) code in +/// the postcondition, e.g. `fstar!("true")`. +/// /// # Example /// /// ``` @@ -268,61 +382,14 @@ pub fn ensures(attr: pm::TokenStream, item: pm::TokenStream) -> pm::TokenStream .into() } -struct ImplFnDecoration { - pub kind: FnDecorationKind, - pub phi: Expr, - pub generics: Generics, - pub self_ty: Type, -} - mod kw { + syn::custom_keyword!(hax_lib); syn::custom_keyword!(decreases); syn::custom_keyword!(ensures); syn::custom_keyword!(requires); syn::custom_keyword!(refine); } -impl parse::Parse for ImplFnDecoration { - fn parse(input: parse::ParseStream) -> Result { - let parse_next = || -> Result<_> { - input.parse::()?; - let mut generics = input.parse::()?; - input.parse::()?; - generics.where_clause = input.parse::>()?; - input.parse::()?; - let self_ty = input.parse::()?; - input.parse::()?; - Ok((generics, self_ty)) - }; - let kind = if let Ok(_) = input.parse::() { - FnDecorationKind::Decreases - } else if let Ok(_) = input.parse::() { - FnDecorationKind::Requires - } else if let Ok(_) = input.parse::() { - let (generics, self_ty) = parse_next()?; - let ExprClosure1 { arg, body } = input.parse::()?; - input.parse::()?; - return Ok(ImplFnDecoration { - kind: FnDecorationKind::Ensures { ret_binder: arg }, - phi: body, - generics, - self_ty, - }); - } else { - return Err(input.lookahead1().error()); - }; - let (generics, self_ty) = parse_next()?; - let phi = input.parse::()?; - input.parse::()?; - Ok(ImplFnDecoration { - kind, - phi, - generics, - self_ty, - }) - } -} - /// Internal macro for dealing with function decorations /// (`#[decreases(...)]`, `#[ensures(...)]`, `#[requires(...)]`) on /// `fn` items within an `impl` block. There is special handling since @@ -346,6 +413,28 @@ pub fn impl_fn_decoration(attr: pm::TokenStream, item: pm::TokenStream) -> pm::T quote! {#attr #item}.into() } +#[proc_macro_error] +#[proc_macro_attribute] +pub fn trait_fn_decoration(attr: pm::TokenStream, item: pm::TokenStream) -> pm::TokenStream { + let ImplFnDecoration { + kind, + phi, + generics, + self_ty, + } = parse_macro_input!(attr); + let mut item: syn::TraitItemFn = parse_macro_input!(item); + let (decoration, attr) = + make_fn_decoration(phi, item.sig.clone(), kind, Some(generics), Some(self_ty)); + let decoration = Stmt::Item(Item::Verbatim(decoration)); + item.sig + .generics + .where_clause + .get_or_insert(parse_quote! {where}) + .predicates + .push(parse_quote! {[(); {#decoration 0}]:}); + quote! {#attr #item}.into() +} + /// Enable the following attrubutes in the annotated item and sub-items: /// - (in a struct) `refine`: refine a type with a logical formula /// - (on a `fn` in an `impl`) `decreases`, `ensures`, `requires`: @@ -380,26 +469,75 @@ pub fn impl_fn_decoration(attr: pm::TokenStream, item: pm::TokenStream) -> pm::T pub fn attributes(_attr: pm::TokenStream, item: pm::TokenStream) -> pm::TokenStream { let item: Item = parse_macro_input!(item); - struct AttrVisitor {} + #[derive(Default)] + struct AttrVisitor { + extra_items: Vec, + } use syn::visit_mut; impl VisitMut for AttrVisitor { + fn visit_item_trait_mut(&mut self, item: &mut ItemTrait) { + let span = item.span(); + for ti in item.items.iter_mut() { + if let TraitItem::Fn(fun) = ti { + for attr in &mut fun.attrs { + let Meta::List(ml) = attr.meta.clone() else { + continue; + }; + let Ok(Some(decoration)) = expects_path_decoration(&ml.path) else { + continue; + }; + let decoration = syn::Ident::new(&decoration, ml.path.span()); + + let mut generics = item.generics.clone(); + let predicate = WherePredicate::Type(PredicateType { + lifetimes: None, + bounded_ty: parse_quote! {Self_}, + colon_token: Token![:](span), + bounds: item.supertraits.clone(), + }); + let mut where_clause = generics + .where_clause + .clone() + .unwrap_or(parse_quote! {where}); + where_clause.predicates.push(predicate.clone()); + generics.where_clause = Some(where_clause.clone()); + let self_ty: Type = parse_quote! {Self_}; + let tokens = ml.tokens.clone(); + let generics = merge_generics(parse_quote! {}, generics); + let ImplFnDecoration { + kind, phi, self_ty, .. + } = parse_quote! {#decoration, #generics, where, #self_ty, #tokens}; + let (decoration, relation_attr) = make_fn_decoration( + phi, + fun.sig.clone(), + kind, + Some(generics), + Some(self_ty), + ); + *attr = parse_quote! {#relation_attr}; + self.extra_items.push(decoration); + } + } + } + visit_mut::visit_item_trait_mut(self, item); + } + fn visit_type_mut(&mut self, _type: &mut Type) {} fn visit_item_impl_mut(&mut self, item: &mut ItemImpl) { for ii in item.items.iter_mut() { if let ImplItem::Fn(fun) = ii { for attr in fun.attrs.iter_mut() { if let Meta::List(ml) = &mut attr.meta { - let decoration = &ml.path; - if decoration.ends_with("requires") - || decoration.ends_with("ensures") - || decoration.ends_with("decreases") - { - let tokens = ml.tokens.clone(); - let (generics, self_ty) = (&item.generics, &item.self_ty); - let where_clause = &generics.where_clause; - ml.tokens = quote! {#decoration, #generics, #where_clause, #self_ty, #tokens}; - ml.path = parse_quote! {::hax_lib::impl_fn_decoration}; - } + let Ok(Some(decoration)) = expects_path_decoration(&ml.path) else { + continue; + }; + let decoration = syn::Ident::new(&decoration, ml.path.span()); + let tokens = ml.tokens.clone(); + let (generics, self_ty) = (&item.generics, &item.self_ty); + let where_clause = &generics.where_clause; + ml.tokens = + quote! {#decoration, #generics, #where_clause, #self_ty, #tokens}; + ml.path = parse_quote! {::hax_lib::impl_fn_decoration}; } } } @@ -470,11 +608,12 @@ pub fn attributes(_attr: pm::TokenStream, item: pm::TokenStream) -> pm::TokenStr } } - let mut v = AttrVisitor {}; + let mut v = AttrVisitor::default(); let mut item = item; v.visit_item_mut(&mut item); + let extra_items = v.extra_items; - quote! { #item }.into() + quote! { #item #(#extra_items)* }.into() } /// Mark a struct or an enum opaque: the extraction will assume the @@ -626,70 +765,82 @@ macro_rules! make_quoting_item_proc_macro { } macro_rules! make_quoting_proc_macro { - ($backend:ident($expr_name:ident, $before_name:ident, $after_name:ident, $replace_name:ident, $cfg_name:ident)) => { - #[doc = concat!("Embed ", stringify!($backend), " expression inside a Rust expression. This macro takes only one argument: some raw ", stringify!($backend), " code as a string literal.")] - /// - - /// While it is possible to directly write raw backend code, - /// sometimes it can be inconvenient. For example, referencing - /// Rust names can be a bit cumbersome: for example, the name - /// `my_crate::my_module::CONSTANT` might be translated - /// differently in a backend (e.g. in the F* backend, it will - /// probably be `My_crate.My_module.v_CONSTANT`). - /// + ($backend:ident) => { + paste::paste! { + #[doc = concat!("Embed ", stringify!($backend), " expression inside a Rust expression. This macro takes only one argument: some raw ", stringify!($backend), " code as a string literal.")] + /// + + /// While it is possible to directly write raw backend code, + /// sometimes it can be inconvenient. For example, referencing + /// Rust names can be a bit cumbersome: for example, the name + /// `my_crate::my_module::CONSTANT` might be translated + /// differently in a backend (e.g. in the F* backend, it will + /// probably be `My_crate.My_module.v_CONSTANT`). + /// + + /// To facilitate this, you can write Rust names directly, + /// using the prefix `$`: `f $my_crate::my_module__CONSTANT + 3` + /// will be replaced with `f My_crate.My_module.v_CONSTANT + 3` + /// in the F* backend for instance. + + /// If you want to refer to the Rust constructor + /// `Enum::Variant`, you should write `$$Enum::Variant` (note + /// the double dollar). + + /// If the name refers to something polymorphic, you need to + /// signal it by adding _any_ type informations, + /// e.g. `${my_module::function<()>}`. The curly braces are + /// needed for such more complex expressions. + + /// You can also write Rust patterns with the `$?{SYNTAX}` + /// syntax, where `SYNTAX` is a Rust pattern. The syntax + /// `${EXPR}` also allows any Rust expressions + /// `EXPR` to be embedded. + + /// Types can be refered to with the syntax `$:{TYPE}`. + #[proc_macro] + pub fn [<$backend _expr>](payload: pm::TokenStream) -> pm::TokenStream { + let ts: TokenStream = quote::expression(true, payload).into(); + quote!{ + #[cfg([< hax_backend_ $backend >])] + { + #ts + } + }.into() + } - /// To facilitate this, you can write Rust names directly, - /// using the prefix `$`: `f $my_crate::my_module__CONSTANT + 3` - /// will be replaced with `f My_crate.My_module.v_CONSTANT + 3` - /// in the F* backend for instance. - - /// If you want to refer to the Rust constructor - /// `Enum::Variant`, you should write `$$Enum::Variant` (note - /// the double dollar). - - /// If the name refers to something polymorphic, you need to - /// signal it by adding _any_ type informations, - /// e.g. `${my_module::function<()>}`. The curly braces are - /// needed for such more complex expressions. - - /// You can also write Rust patterns with the `$?{SYNTAX}` - /// syntax, where `SYNTAX` is a Rust pattern. The syntax - /// `${EXPR}` also allows any Rust expressions - /// `EXPR` to be embedded. - - /// Types can be refered to with the syntax `$:{TYPE}`. - #[proc_macro] - pub fn $expr_name(payload: pm::TokenStream) -> pm::TokenStream { - let ts: TokenStream = quote::expression(payload).into(); - quote!{ - #[cfg($cfg_name)] - { - #ts - } - }.into() - } + #[doc = concat!("The unsafe (because polymorphic: even computationally relevant code can be inlined!) version of `", stringify!($backend), "_expr`.")] + #[proc_macro] + #[doc(hidden)] + pub fn [<$backend _unsafe_expr>](payload: pm::TokenStream) -> pm::TokenStream { + let ts: TokenStream = quote::expression(false, payload).into(); + quote!{ + #[cfg([< hax_backend_ $backend >])] + { + #ts + } + }.into() + } - make_quoting_item_proc_macro!($backend, $before_name, ItemQuotePosition::Before, $cfg_name); - make_quoting_item_proc_macro!($backend, $after_name, ItemQuotePosition::After, $cfg_name); + make_quoting_item_proc_macro!($backend, [< $backend _before >], ItemQuotePosition::Before, [< hax_backend_ $backend >]); + make_quoting_item_proc_macro!($backend, [< $backend _after >], ItemQuotePosition::After, [< hax_backend_ $backend >]); - #[doc = concat!("Replaces a Rust expression with some verbatim ", stringify!($backend)," code.")] - #[proc_macro_error] - #[proc_macro_attribute] - pub fn $replace_name(payload: pm::TokenStream, item: pm::TokenStream) -> pm::TokenStream { - let item: TokenStream = item.into(); - let attr = AttrPayload::ItemStatus(ItemStatus::Included { late_skip: true }); - $before_name(payload, quote!{#attr #item}.into()) + #[doc = concat!("Replaces a Rust expression with some verbatim ", stringify!($backend)," code.")] + #[proc_macro_error] + #[proc_macro_attribute] + pub fn [< $backend _replace >](payload: pm::TokenStream, item: pm::TokenStream) -> pm::TokenStream { + let item: TokenStream = item.into(); + let attr = AttrPayload::ItemStatus(ItemStatus::Included { late_skip: true }); + [< $backend _before >](payload, quote!{#attr #item}.into()) + } } }; - ($backend:ident $payload:tt $($others:tt)+) => { - make_quoting_proc_macro!($backend$payload); - make_quoting_proc_macro!($($others)+); + ($($backend:ident)*) => { + $(make_quoting_proc_macro!($backend);)* } } -make_quoting_proc_macro!(fstar(fstar_expr, fstar_before, fstar_after, fstar_replace, hax_backend_fstar) - coq(coq_expr, coq_before, coq_after, coq_replace, hax_backend_coq) - proverif(proverif_expr, proverif_before, proverif_after, proverif_replace, hax_backend_proverif)); +make_quoting_proc_macro!(fstar coq proverif); /// Marks a newtype `struct RefinedT(T);` as a refinement type. The /// struct should have exactly one unnamed private field. @@ -820,6 +971,9 @@ pub fn refinement_type(mut attr: pm::TokenStream, item: pm::TokenStream) -> pm:: quote! { #[allow(non_snake_case)] mod #module_ident { + #[allow(unused_imports)] + use super::*; + #refinement_item #newtype_as_ref_attr @@ -828,7 +982,9 @@ pub fn refinement_type(mut attr: pm::TokenStream, item: pm::TokenStream) -> pm:: #[::hax_lib::exclude] impl #generics ::hax_lib::Refinement for #ident <#generics_args> { + type InnerType = #inner_ty; + fn new(x: Self::InnerType) -> Self { #debug_assert Self(x) @@ -836,6 +992,9 @@ pub fn refinement_type(mut attr: pm::TokenStream, item: pm::TokenStream) -> pm:: fn get(self) -> Self::InnerType { self.0 } + fn get_mut(&mut self) -> &mut Self::InnerType { + &mut self.0 + } fn invariant(#ret_binder: Self::InnerType) -> bool { #phi } diff --git a/hax-lib-macros/src/quote.rs b/hax-lib-macros/src/quote.rs index b06927817..6bd5282f1 100644 --- a/hax-lib-macros/src/quote.rs +++ b/hax-lib-macros/src/quote.rs @@ -13,7 +13,6 @@ //! - `:`, the antiquotation is a type. use crate::prelude::*; -use quote::ToTokens; /// Marker that indicates a place where a antiquotation will be inserted const SPLIT_MARK: &str = "SPLIT_QUOTE"; @@ -135,7 +134,7 @@ pub(super) fn item( payload: pm::TokenStream, item: pm::TokenStream, ) -> pm::TokenStream { - let expr = TokenStream::from(expression(payload)); + let expr = TokenStream::from(expression(true, payload)); let item = TokenStream::from(item); let uid = ItemUid::fresh(); let uid_attr = AttrPayload::Uid(uid.clone()); @@ -163,7 +162,22 @@ pub(super) fn item( .into() } -pub(super) fn expression(payload: pm::TokenStream) -> pm::TokenStream { +pub(super) fn detect_future_node_in_expression(e: &syn::Expr) -> bool { + struct Visitor(bool); + use syn::visit::*; + impl<'a> Visit<'a> for Visitor { + fn visit_expr(&mut self, e: &'a Expr) { + if let Some(Ok(_)) = crate::utils::expect_future_expr(e) { + self.0 = true; + } + } + } + let mut visitor = Visitor(false); + visitor.visit_expr(e); + visitor.0 +} + +pub(super) fn expression(force_unit: bool, payload: pm::TokenStream) -> pm::TokenStream { let (mut backend_code, antiquotes) = { let payload = parse_macro_input!(payload as LitStr).value(); if payload.find(SPLIT_MARK).is_some() { @@ -179,8 +193,18 @@ pub(super) fn expression(payload: pm::TokenStream) -> pm::TokenStream { .collect(); (quote! {#string}, antiquotes) }; - for user in antiquotes.iter().rev() { + if !force_unit + && syn::parse(user.ts.clone()) + .as_ref() + .map(detect_future_node_in_expression) + .unwrap_or(false) + { + let ts: proc_macro2::TokenStream = user.ts.clone().into(); + return quote! { + ::std::compile_error!(concat!("The `future` operator cannot be used within a quote. Hint: move `", stringify!(#ts), "` to a let binding and use the binding name instead.")) + }.into(); + } let kind = &user.kind; backend_code = quote! { let #kind = #user; @@ -188,5 +212,14 @@ pub(super) fn expression(payload: pm::TokenStream) -> pm::TokenStream { }; } - quote! {::hax_lib::inline(#[allow(unused_variables)]{#backend_code})}.into() + let function = if force_unit { + quote! {inline} + } else { + quote! {inline_unsafe} + }; + + quote! { + ::hax_lib::#function(#[allow(unused_variables)]{#backend_code}) + } + .into() } diff --git a/hax-lib-macros/src/rewrite_self.rs b/hax-lib-macros/src/rewrite_self.rs index 8df936d22..364f4d88a 100644 --- a/hax-lib-macros/src/rewrite_self.rs +++ b/hax-lib-macros/src/rewrite_self.rs @@ -1,30 +1,82 @@ +use crate::syn_ext::*; use proc_macro2::Span; use syn::spanned::Spanned; use syn::*; +/// The `RewriteSelf` structure is hidden in a module so that only its +/// method can mutate its fields. mod rewrite_self { use super::*; + use std::collections::HashSet; + + /// Small & dirty wrapper around spans to make them `Eq`, + /// `PartialEq` and `Hash` + #[derive(Clone, Debug)] + struct SpanWrapper(Span); + const _: () = { + impl Eq for SpanWrapper {} + impl PartialEq for SpanWrapper { + fn eq(&self, other: &Self) -> bool { + format!("{self:?}") == format!("{other:?}") + } + } + use std::hash::*; + impl Hash for SpanWrapper { + fn hash(&self, state: &mut H) { + format!("{self:?}").hash(state) + } + } + }; + + /// A struct that carries informations for substituting `self` and + /// `Self`. Note `typ` is an option: + #[must_use] pub struct RewriteSelf { - self_detected: bool, typ: Option, ident: Ident, + self_spans: HashSet, } + impl RewriteSelf { - pub fn self_ident(&mut self) -> Ident { - self.self_detected = true; - self.ident.clone() + /// Consumes `RewriteSelf`, optionally outputing errors. + pub fn get_error(self) -> Option { + if self.typ.is_some() || self.self_spans.is_empty() { + return None; + } + + let mut error = Error::new(Span::call_site(), "This macro doesn't work on trait or impl items: you need to add a `#[hax_lib::attributes]` on the enclosing impl block or trait."); + for SpanWrapper(span) in self.self_spans { + let use_site = Error::new( + span, + "Here, the function you are trying to annotate has a `Self`.", + ); + error.combine(use_site); + } + Some(error.to_compile_error()) + } + + fn self_detected(&mut self, span: Span) { + self.self_spans.insert(SpanWrapper(span)); } + + /// Requests the ident with which `self` should be substituted. + pub fn self_ident(&mut self, span: Span) -> &Ident { + self.self_detected(span); + &self.ident + } + /// Requests the type with which `Self` should be substituted with. pub fn self_ty(&mut self, span: Span) -> Type { - self.self_detected = true; + self.self_detected(span); self.typ.clone().unwrap_or_else(|| { - Type::Verbatim(Error::new(span, "Detected a `self`").to_compile_error()) + parse_quote! {Self} }) } + /// Construct a rewritter pub fn new(ident: Ident, typ: Option) -> Self { Self { typ, ident, - self_detected: false, + self_spans: HashSet::new(), } } } @@ -32,47 +84,34 @@ mod rewrite_self { pub use rewrite_self::*; impl visit_mut::VisitMut for RewriteSelf { - fn visit_expr_path_mut(&mut self, i: &mut ExprPath) { - let ExprPath { - qself: None, - path: - Path { - leading_colon: None, - segments, - }, - .. - } = i - else { - return (); - }; - if segments.len() != 1 { - return (); + fn visit_expr_mut(&mut self, e: &mut Expr) { + visit_mut::visit_expr_mut(self, e); + if e.is_ident("self") { + let into = self.self_ident(e.span()).clone(); + *e = parse_quote! {#into} } - let Some(PathSegment { - ident, - arguments: PathArguments::None, - }) = segments.first_mut() - else { - return (); - }; - if ident.to_string() == "self" { - let into = self.self_ident().clone(); - *ident = parse_quote! {#into} + } + fn visit_type_mut(&mut self, ty: &mut Type) { + visit_mut::visit_type_mut(self, ty); + if ty.is_ident("Self") { + *ty = self.self_ty(ty.span()) } } fn visit_fn_arg_mut(&mut self, arg: &mut FnArg) { + visit_mut::visit_fn_arg_mut(self, arg); if let FnArg::Receiver(r) = arg { + let span = r.self_token.span(); *arg = FnArg::Typed(PatType { attrs: r.attrs.clone(), pat: Box::new(Pat::Ident(PatIdent { attrs: vec![], by_ref: None, mutability: None, - ident: self.self_ident().clone(), + ident: self.self_ident(span.clone()).clone(), subpat: None, })), colon_token: token::Colon(arg.span()), - ty: Box::new(self.self_ty(arg.span())), + ty: Box::new(self.self_ty(span.clone())), }); } } diff --git a/hax-lib-macros/src/syn_ext.rs b/hax-lib-macros/src/syn_ext.rs index c9a5e7312..83e8dd746 100644 --- a/hax-lib-macros/src/syn_ext.rs +++ b/hax-lib-macros/src/syn_ext.rs @@ -1,25 +1,16 @@ use crate::prelude::*; use syn::parse::*; +use syn::punctuated::Punctuated; /// A closure expression of arity 1, e.g. `|x| x + 3` pub struct ExprClosure1 { - pub arg: syn::Pat, - pub body: syn::Expr, -} - -pub trait PatExt { - // Make sure to remove type ascriptions - fn untype(mut pat: syn::Pat) -> syn::Pat { - if let syn::Pat::Type(sub) = pat { - pat = *sub.pat.clone(); - } - pat - } + pub arg: Pat, + pub body: Expr, } impl Parse for ExprClosure1 { fn parse(ps: ParseStream) -> Result { - let closure: syn::ExprClosure = Parse::parse(ps as ParseStream)?; + let closure: ExprClosure = Parse::parse(ps as ParseStream)?; let inputs = closure.inputs; if inputs.len() != 1 { Err(Error::new(inputs.span(), "Expected exactly one argument"))?; @@ -37,13 +28,96 @@ pub trait PathExt { /// attribute from an attribute from another crate that share a /// common name. fn ends_with(&self, i: &str) -> bool; + + /// Expects a simple path (no `<...>`). + fn expect_simple_path(&self) -> Option>; } impl PathExt for Path { fn ends_with(&self, i: &str) -> bool { - matches!(self.segments.iter().last(), Some(syn::PathSegment { + matches!(self.segments.iter().last(), Some(PathSegment { ident, - arguments: syn::PathArguments::None, + arguments: PathArguments::None, }) if i == ident.to_string().as_str()) } + + fn expect_simple_path(&self) -> Option> { + let mut chunks = vec![]; + if self.leading_colon.is_some() { + chunks.push(String::new()) + } + for segment in &self.segments { + chunks.push(format!("{}", segment.ident)); + if !matches!(segment.arguments, PathArguments::None) { + return None; + } + } + return Some(chunks); + } +} + +/// Utility trait to extract an `Ident` from various syn types +pub trait ExpectIdent { + /// Is `self` an `Ident`? + fn expect_ident(&self) -> Option; + /// Is `self` a specific ident named `name`? + fn is_ident(&self, name: &str) -> bool { + self.expect_ident() + .filter(|ident| &ident.to_string() == name) + .is_some() + } +} + +impl ExpectIdent for Box { + fn expect_ident(&self) -> Option { + let this: &T = &*self; + this.expect_ident() + } +} + +fn expect_punctuated_1(x: &Punctuated) -> Option { + (x.len() == 1).then(|| x.first().unwrap().clone()) +} + +impl ExpectIdent for Path { + fn expect_ident(&self) -> Option { + expect_punctuated_1(&self.segments).map(|s| s.ident) + } +} + +impl ExpectIdent for Expr { + fn expect_ident(&self) -> Option { + match self { + Expr::Path(ExprPath { + qself: None, path, .. + }) => path.expect_ident(), + _ => None, + } + } +} + +impl ExpectIdent for Type { + fn expect_ident(&self) -> Option { + match self { + Type::Path(TypePath { + qself: None, path, .. + }) => path.expect_ident(), + _ => None, + } + } +} + +impl ExpectIdent for Pat { + fn expect_ident(&self) -> Option { + match self { + Pat::Ident(PatIdent { + by_ref: None, + mutability: None, + ident, + subpat: None, + .. + }) => Some(ident.clone()), + _ => None, + } + } } diff --git a/hax-lib-macros/src/utils.rs b/hax-lib-macros/src/utils.rs index 4c9247b27..b155855e8 100644 --- a/hax-lib-macros/src/utils.rs +++ b/hax-lib-macros/src/utils.rs @@ -1,20 +1,6 @@ use crate::prelude::*; use crate::rewrite_self::*; -pub trait BlockExt { - /// Bring in the scope of the block quantifiers helpers (the `forall` and `exists` functions) - fn make_quantifiers_available(&mut self); -} - -impl BlockExt for Block { - fn make_quantifiers_available(&mut self) { - self.stmts.insert( - 0, - Stmt::Item(Item::Verbatim(HaxQuantifiers.to_token_stream())), - ); - } -} - /// `HaxQuantifiers` expands to the definition of the `forall` and `exists` functions pub struct HaxQuantifiers; impl ToTokens for HaxQuantifiers { @@ -31,6 +17,10 @@ impl ToTokens for HaxQuantifiers { fn exists bool>(f: F) -> bool { true } + + use ::hax_lib::fstar_unsafe_expr as fstar; + use ::hax_lib::coq_unsafe_expr as coq; + use ::hax_lib::proverif_unsafe_expr as proverif; } .to_tokens(tokens) } @@ -64,7 +54,7 @@ impl From for AssociationRole { } /// Merge two `syn::Generics`, respecting lifetime orders -fn merge_generics(x: Generics, y: Generics) -> Generics { +pub(crate) fn merge_generics(x: Generics, y: Generics) -> Generics { Generics { lt_token: x.lt_token.or(y.lt_token), gt_token: x.gt_token.or(y.gt_token), @@ -102,9 +92,10 @@ fn merge_generics(x: Generics, y: Generics) -> Generics { } } -/// Transform every `x: &mut T` input into `x: &T` in a signature -fn unmut_references_in_inputs(sig: &mut Signature) -> bool { - let mut any_mut_ref = false; +/// Transform every `x: &mut T` input into `x: &T` in a signature, and +/// returns a list of such transformed `x: &T` inputs +fn unmut_references_in_inputs(sig: &mut Signature) -> Vec { + let mut mutable_inputs = vec![]; for input in &mut sig.inputs { if let Some(mutability) = match input { FnArg::Receiver(syn::Receiver { @@ -123,11 +114,104 @@ fn unmut_references_in_inputs(sig: &mut Signature) -> bool { } _ => None, } { - any_mut_ref |= mutability.is_some(); - *mutability = None; + if mutability.is_some() { + *mutability = None; + mutable_inputs.push(input.clone()); + } + } + } + mutable_inputs +} + +/// Expects a `FnArg` to be a simple variable pattern +fn expect_fn_arg_var_pat(arg: &FnArg) -> Option<(String, syn::Type)> { + match arg { + FnArg::Receiver(recv) => Some(("self".into(), *recv.ty.clone())), + FnArg::Typed(pat_type) => match &*pat_type.pat { + syn::Pat::Wild(_) => Some(("".into(), *pat_type.ty.clone())), + syn::Pat::Ident(pat_ident) => { + Some((format!("{}", pat_ident.ident), *pat_type.ty.clone())) + } + _ => None, + }, + } +} + +pub(crate) enum NotFutureExpr { + BadNumberOfArgs, + ArgNotIdent, +} + +/// `expect_future_expr(e)` tries to match the pattern +/// `future()` in expression `e` +pub(crate) fn expect_future_expr(e: &Expr) -> Option> { + if let Expr::Call(call) = e { + if call.func.is_ident("future") { + return Some(match call.args.iter().collect::>().as_slice() { + [arg] => arg.expect_ident().ok_or(NotFutureExpr::ArgNotIdent), + _ => Err(NotFutureExpr::BadNumberOfArgs), + }); + } + } + None +} + +/// Rewrites `future(x)` nodes in an expression when (1) `x` is an +/// ident and (2) the ident `x` is contained in the HashSet. +struct RewriteFuture(HashSet); +impl VisitMut for RewriteFuture { + fn visit_expr_mut(&mut self, e: &mut Expr) { + syn::visit_mut::visit_expr_mut(self, e); + let error = match expect_future_expr(e) { + Some(Ok(arg)) => { + let arg = format!("{}", arg); + if self.0.contains(&arg) { + let arg = create_future_ident(&arg); + *e = parse_quote! {#arg}; + return; + } + Some(format!("Cannot find an input `{arg}` of type `&mut _`. In the context, `future` can be called on the following inputs: {:?}.", self.0)) + } + Some(Err(error_kind)) => { + let message = match error_kind { + NotFutureExpr::BadNumberOfArgs => { + "`future` can only be called with one argument: a `&mut` input name" + } + NotFutureExpr::ArgNotIdent => { + "`future` can only be called with an `&mut` input name" + } + }; + let help_message = match self.0.iter().next() { + None => format!(" In the context, there is no `&mut` input."), + Some(var) => { + format!(" For example, in the context you can write `future({var})`.") + } + }; + Some(format!("{message}.{}", help_message)) + } + None => None, + }; + if let Some(error) = error { + *e = parse_quote! {::std::compile_error!(#error)}; } } - any_mut_ref +} + +fn create_future_ident(name: &str) -> syn::Ident { + proc_macro2::Ident::new(&format!("{name}_future"), proc_macro2::Span::call_site()) +} + +/// The engine translates functions of arity zero to functions that +/// takes exactly one unit argument. The zero-arity functions we +/// generate are translated correctly as well. But in the case of a +/// `ensures` clause, that's an issue: we produce a function of arity +/// one, whose first argument is the result of the function. Instead, +/// we need a function of arity two. +/// `fix_signature_arity` adds a `unit` if needed. +fn add_unit_to_sig_if_needed(signature: &mut Signature) { + if signature.inputs.is_empty() { + signature.inputs.push(parse_quote! {_: ()}) + } } /// Common logic when generating a function decoration @@ -135,29 +219,63 @@ pub fn make_fn_decoration( mut phi: Expr, mut signature: Signature, kind: FnDecorationKind, - generics: Option, + mut generics: Option, self_type: Option, ) -> (TokenStream, AttrPayload) { let uid = ItemUid::fresh(); - let any_mut_ref = unmut_references_in_inputs(&mut signature); - if any_mut_ref && matches!(kind, FnDecorationKind::Ensures { .. }) { - panic!("For now, ensures clause don't work on function that have `&mut` inputs (see https://github.com/hacspec/hax/issues/290)") - } - + let mut_ref_inputs = unmut_references_in_inputs(&mut signature); let self_ident: Ident = syn::parse_quote! {self_}; - let mut rewriter = RewriteSelf::new(self_ident, self_type); - rewriter.visit_expr_mut(&mut phi); + let error = { + let mut rewriter = RewriteSelf::new(self_ident, self_type); + rewriter.visit_expr_mut(&mut phi); + rewriter.visit_signature_mut(&mut signature); + if let Some(generics) = generics.as_mut() { + rewriter.visit_generics_mut(generics); + } + rewriter.get_error() + }; let decoration = { let decoration_sig = { - let mut sig = signature; - rewriter.visit_signature_mut(&mut sig); + let mut sig = signature.clone(); sig.ident = format_ident!("{}", kind.to_string()); if let FnDecorationKind::Ensures { ret_binder } = &kind { - let output = match sig.output { - syn::ReturnType::Default => quote! {()}, - syn::ReturnType::Type(_, t) => quote! {#t}, + add_unit_to_sig_if_needed(&mut sig); + let output_typ = match sig.output { + syn::ReturnType::Default => parse_quote! {()}, + syn::ReturnType::Type(_, t) => t, }; - sig.inputs.push(syn::parse_quote! {#ret_binder: #output}); + let mut_ref_inputs = mut_ref_inputs + .iter() + .map(|mut_ref_input| { + expect_fn_arg_var_pat(mut_ref_input).expect( + "Every `&mut` input of a function annotated with a `ensures` clause is expected to be a simple variable pattern.", + ) + }); + let mut rewrite_future = + RewriteFuture(mut_ref_inputs.clone().map(|x| x.0).collect()); + rewrite_future.visit_expr_mut(&mut phi); + let (mut pats, mut tys): (Vec<_>, Vec<_>) = mut_ref_inputs + .map(|(name, ty)| { + ( + create_future_ident(&name).to_token_stream(), + ty.to_token_stream(), + ) + }) + .unzip(); + + let is_output_typ_unit = if let syn::Type::Tuple(tuple) = &*output_typ { + tuple.elems.is_empty() + } else { + false + }; + + if !is_output_typ_unit || pats.is_empty() { + pats.push(ret_binder.to_token_stream()); + tys.push(quote! {#output_typ}); + } + + sig.inputs + .push(syn::parse_quote! {(#(#pats),*): (#(#tys),*)}); } if let Some(generics) = generics { sig.generics = merge_generics(generics, sig.generics); @@ -210,5 +328,5 @@ pub fn make_fn_decoration( role: kind.into(), item: uid, }; - (decoration, assoc_attr) + (quote! {#error #decoration}, assoc_attr) } diff --git a/hax-lib/Cargo.toml b/hax-lib/Cargo.toml index 299fd8b8e..5207f0e7b 100644 --- a/hax-lib/Cargo.toml +++ b/hax-lib/Cargo.toml @@ -17,3 +17,6 @@ num-traits = { version = "0.2.15", default-features = false } [features] default = ["macros"] macros = ["dep:hax-lib-macros"] + +[lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = ['cfg(hax)'] } diff --git a/hax-lib/proofs/fstar/extraction/Hax_lib.Int.fst b/hax-lib/proofs/fstar/extraction/Hax_lib.Int.fst index 9e8e7feb5..053d483c4 100644 --- a/hax-lib/proofs/fstar/extraction/Hax_lib.Int.fst +++ b/hax-lib/proofs/fstar/extraction/Hax_lib.Int.fst @@ -3,7 +3,6 @@ module Hax_lib.Int open Core unfold type t_Int = int -unfold type impl__Int__to_u16 unfold let impl__Int__to_u8 (#t:inttype) (n:range_t t) : int_t t = mk_int #t n unfold let impl__Int__to_u16 (#t:inttype) (n:range_t t) : int_t t = mk_int #t n diff --git a/hax-lib/src/lib.rs b/hax-lib/src/lib.rs index 9ebb361b9..1b2b1b4d1 100644 --- a/hax-lib/src/lib.rs +++ b/hax-lib/src/lib.rs @@ -141,6 +141,16 @@ pub fn implies(lhs: bool, rhs: impl Fn() -> bool) -> bool { #[doc(hidden)] pub fn inline(_: &str) {} +/// Similar to `inline`, but allows for any type. Do not use directly. +#[doc(hidden)] +pub fn inline_unsafe(_: &str) -> T { + unreachable!() +} + +/// A dummy function that holds a loop invariant. +#[doc(hidden)] +pub fn _internal_loop_invariant bool>(_: P) {} + /// A type that implements `Refinement` should be a newtype for a /// type `T`. The field holding the value of type `T` should be /// private, and `Refinement` should be the only interface to the @@ -156,6 +166,8 @@ pub trait Refinement { fn new(x: Self::InnerType) -> Self; /// Destructor for the refined type fn get(self) -> Self::InnerType; + /// Gets a mutable reference to a refinement + fn get_mut(&mut self) -> &mut Self::InnerType; /// Tests wether a value satisfies the refinement fn invariant(value: Self::InnerType) -> bool; } diff --git a/hax-lib/src/proc_macros.rs b/hax-lib/src/proc_macros.rs index 7d87111f1..866c7cfda 100644 --- a/hax-lib/src/proc_macros.rs +++ b/hax-lib/src/proc_macros.rs @@ -2,8 +2,8 @@ //! proc-macro crate cannot export anything but procedural macros. pub use hax_lib_macros::{ - attributes, ensures, exclude, impl_fn_decoration, include, lemma, opaque_type, refinement_type, - requires, + attributes, ensures, exclude, impl_fn_decoration, include, lemma, loop_invariant, opaque_type, + refinement_type, requires, trait_fn_decoration, }; pub use hax_lib_macros::{ @@ -11,14 +11,17 @@ pub use hax_lib_macros::{ }; macro_rules! export_quoting_proc_macros { - ($backend:ident($expr_name:ident, $before_name:ident, $after_name:ident, $replace_name:ident, $cfg_name:ident)) => { + ($backend:ident($expr_name:ident, $expr_unsafe_name:ident, $before_name:ident, $after_name:ident, $replace_name:ident, $cfg_name:ident $(, {$($extra:tt)+})?)) => { pub use hax_lib_macros::$expr_name as $backend; + #[doc(hidden)] + pub use hax_lib_macros::$expr_unsafe_name; #[doc=concat!("Procedural macros for ", stringify!($backend))] pub mod $backend { pub use hax_lib_macros::$after_name as after; pub use hax_lib_macros::$before_name as before; pub use hax_lib_macros::$replace_name as replace; + $($($extra)*)? } }; @@ -28,6 +31,12 @@ macro_rules! export_quoting_proc_macros { } } -export_quoting_proc_macros!(fstar(fstar_expr, fstar_before, fstar_after, fstar_replace, hax_backend_fstar) - coq(coq_expr, coq_before, coq_after, coq_replace, hax_backend_coq) - proverif(proverif_expr, proverif_before, proverif_after, proverif_replace, hax_backend_proverif)); +export_quoting_proc_macros!( + fstar(fstar_expr, fstar_unsafe_expr, fstar_before, fstar_after, fstar_replace, hax_backend_fstar, { + pub use hax_lib_macros::fstar_options as options; + pub use hax_lib_macros::fstar_verification_status as verification_status; + }) + + coq(coq_expr, coq_unsafe_expr, coq_before, coq_after, coq_replace, hax_backend_coq) + + proverif(proverif_expr, proverif_unsafe_expr, proverif_before, proverif_after, proverif_replace, hax_backend_proverif)); diff --git a/cli/options/engine/Cargo.toml b/hax-types/Cargo.toml similarity index 57% rename from cli/options/engine/Cargo.toml rename to hax-types/Cargo.toml index 2a649bb7b..c273670f2 100644 --- a/cli/options/engine/Cargo.toml +++ b/hax-types/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "hax-cli-options-engine" +name = "hax-types" version.workspace = true authors.workspace = true license.workspace = true @@ -7,17 +7,21 @@ homepage.workspace = true edition.workspace = true repository.workspace = true readme.workspace = true -description = "Defines the data type of the input of the engine. The (OCaml) engine reads JSON on stdin and deserializes the payload according to the JSON Schemas defined by this crate." [dependencies] -serde.workspace = true -serde_json.workspace = true -schemars.workspace = true -itertools.workspace = true -clap.workspace = true -hax-diagnostics.workspace = true -hax-cli-options.workspace = true +clap = { workspace = true, features = ["env"] } hax-frontend-exporter.workspace = true hax-frontend-exporter-options.workspace = true +itertools.workspace = true path-clean = "1.0.1" +schemars.workspace = true +serde.workspace = true +colored.workspace = true +serde_json.workspace = true +annotate-snippets.workspace = true +hax-adt-into.workspace = true +bincode.workspace = true +zstd = "0.13.1" +[features] +rustc = ["hax-frontend-exporter/rustc"] diff --git a/hax-types/README.md b/hax-types/README.md new file mode 100644 index 000000000..ee5f1fb81 --- /dev/null +++ b/hax-types/README.md @@ -0,0 +1,8 @@ +# `hax-types` +This crate contains the type definitions that are used to communicate between: + - the command line (the `cargo-hax` binary); + - the custom rustc driver; + - the hax engine (the `hax-engine` binary). + +Those three component send and receive messages in JSON or CBOR on +stdin and stdout. diff --git a/cli/options/build.rs b/hax-types/build.rs similarity index 100% rename from cli/options/build.rs rename to hax-types/build.rs diff --git a/cli/options/src/lib.rs b/hax-types/src/cli_options.rs similarity index 81% rename from cli/options/src/lib.rs rename to hax-types/src/cli_options.rs index c50fdc8c8..aa7a575b5 100644 --- a/cli/options/src/lib.rs +++ b/hax-types/src/cli_options.rs @@ -1,12 +1,12 @@ +use crate::prelude::*; + use clap::{Parser, Subcommand, ValueEnum}; -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; use std::fmt; -use std::path::{Path, PathBuf}; pub use hax_frontend_exporter_options::*; -#[derive(JsonSchema, Debug, Clone, Serialize, Deserialize)] +#[derive_group(Serializers)] +#[derive(JsonSchema, Debug, Clone)] pub enum DebugEngineMode { File(PathOrDash), Interactive, @@ -21,34 +21,29 @@ impl std::convert::From<&str> for DebugEngineMode { } } -#[derive(JsonSchema, Debug, Clone, Serialize, Deserialize)] +#[derive_group(Serializers)] +#[derive(JsonSchema, Debug, Clone, Default)] pub struct ForceCargoBuild { - pub data: u128, -} - -impl std::default::Default for ForceCargoBuild { - fn default() -> Self { - ForceCargoBuild { data: 0 } - } + pub data: u64, } impl std::convert::From<&str> for ForceCargoBuild { fn from(s: &str) -> Self { use std::time::{SystemTime, UNIX_EPOCH}; if s == "false" { - ForceCargoBuild { - data: SystemTime::now() - .duration_since(UNIX_EPOCH) - .map(|r| r.as_millis()) - .unwrap_or(0), - } + let data = SystemTime::now() + .duration_since(UNIX_EPOCH) + .map(|r| r.as_millis()) + .unwrap_or(0); + ForceCargoBuild { data: data as u64 } } else { ForceCargoBuild::default() } } } -#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] +#[derive_group(Serializers)] +#[derive(Debug, Clone, JsonSchema)] pub enum PathOrDash { Dash, Path(PathBuf), @@ -113,7 +108,8 @@ impl NormalizePaths for PathOrDash { } } -#[derive(JsonSchema, Parser, Debug, Clone, Serialize, Deserialize)] +#[derive_group(Serializers)] +#[derive(JsonSchema, Parser, Debug, Clone)] pub struct ProVerifOptions { /// Items for which hax should extract a default-valued process /// macro with a corresponding type signature. This flag expects a @@ -132,7 +128,8 @@ pub struct ProVerifOptions { assume_items: Vec, } -#[derive(JsonSchema, Parser, Debug, Clone, Serialize, Deserialize)] +#[derive_group(Serializers)] +#[derive(JsonSchema, Parser, Debug, Clone)] pub struct FStarOptions { /// Set the Z3 per-query resource limit #[arg(long, default_value = "15")] @@ -162,9 +159,13 @@ pub struct FStarOptions { allow_hyphen_values(true) )] interfaces: Vec, + + #[arg(long, default_value = "100", env = "HAX_FSTAR_LINE_WIDTH")] + line_width: u16, } -#[derive(JsonSchema, Subcommand, Debug, Clone, Serialize, Deserialize)] +#[derive_group(Serializers)] +#[derive(JsonSchema, Subcommand, Debug, Clone)] pub enum Backend { /// Use the F* backend Fstar(FStarOptions), @@ -190,14 +191,16 @@ impl fmt::Display for Backend { } } -#[derive(JsonSchema, Debug, Clone, Serialize, Deserialize)] +#[derive_group(Serializers)] +#[derive(JsonSchema, Debug, Clone)] enum DepsKind { Transitive, Shallow, None, } -#[derive(JsonSchema, Debug, Clone, Serialize, Deserialize)] +#[derive_group(Serializers)] +#[derive(JsonSchema, Debug, Clone)] enum InclusionKind { /// `+query` include the items selected by `query` Included(DepsKind), @@ -205,7 +208,8 @@ enum InclusionKind { Excluded, } -#[derive(JsonSchema, Debug, Clone, Serialize, Deserialize)] +#[derive_group(Serializers)] +#[derive(JsonSchema, Debug, Clone)] struct InclusionClause { kind: InclusionKind, namespace: Namespace, @@ -241,7 +245,8 @@ fn parse_inclusion_clause( }) } -#[derive(JsonSchema, Parser, Debug, Clone, Serialize, Deserialize)] +#[derive_group(Serializers)] +#[derive(JsonSchema, Parser, Debug, Clone)] pub struct TranslationOptions { /// Controls which Rust item should be extracted or not. /// @@ -283,7 +288,8 @@ pub struct TranslationOptions { include_namespaces: Vec, } -#[derive(JsonSchema, Parser, Debug, Clone, Serialize, Deserialize)] +#[derive_group(Serializers)] +#[derive(JsonSchema, Parser, Debug, Clone)] pub struct BackendOptions { #[command(subcommand)] pub backend: Backend, @@ -313,12 +319,28 @@ pub struct BackendOptions { #[arg(short, long = "debug-engine")] pub debug_engine: Option, + /// Extract type aliases. This is disabled by default, since + /// extracted terms depends on expanded types rather than on type + /// aliases. Turning this option on is discouraged: Rust type + /// synonyms can ommit generic bounds, which are ususally + /// necessary in the hax backends, leading to typechecking + /// errors. For more details see + /// https://github.com/hacspec/hax/issues/708. + #[arg(long)] + pub extract_type_aliases: bool, + #[command(flatten)] pub translation_options: TranslationOptions, + + /// Where to put the output files resulting from the translation. + /// Defaults to "/proofs//extraction". + #[arg(long)] + pub output_dir: Option, } -#[derive(JsonSchema, Subcommand, Debug, Clone, Serialize, Deserialize)] -pub enum ExporterCommand { +#[derive_group(Serializers)] +#[derive(JsonSchema, Subcommand, Debug, Clone)] +pub enum Command { /// Translate to a backend. The translated modules will be written /// under the directory `/proofs//extraction`, where /// `` is the translated cargo package name and `` @@ -354,32 +376,24 @@ pub enum ExporterCommand { }, } -#[derive( - JsonSchema, ValueEnum, Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, -)] +impl Command { + pub fn body_kinds(&self) -> Vec { + match self { + Command::JSON { kind, .. } => kind.clone(), + _ => vec![ExportBodyKind::Thir], + } + } +} + +#[derive_group(Serializers)] +#[derive(JsonSchema, ValueEnum, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] pub enum ExportBodyKind { Thir, MirBuilt, - MirConst, -} - -#[derive(JsonSchema, Subcommand, Debug, Clone, Serialize, Deserialize)] -pub enum LinterCommand { - /// Lint for the hacspec subset - Hacspec, - /// Lint for the supported Rust subset - Rust, -} - -#[derive(JsonSchema, Subcommand, Debug, Clone, Serialize, Deserialize)] -pub enum Command { - #[command(flatten)] - ExporterCommand(ExporterCommand), - #[clap(subcommand, name = "lint", about = "Lint the code")] - LintCommand(LinterCommand), } -#[derive(JsonSchema, Parser, Debug, Clone, Serialize, Deserialize)] +#[derive_group(Serializers)] +#[derive(JsonSchema, Parser, Debug, Clone)] #[command(author, version = concat!("commit=", env!("HAX_GIT_COMMIT_HASH"), " ", "describe=", env!("HAX_GIT_DESCRIBE")), name = "hax", about, long_about = None)] pub struct Options { /// Replace the expansion of each macro matching PATTERN by their @@ -409,10 +423,10 @@ pub struct Options { pub cargo_flags: Vec, #[command(subcommand)] - pub command: Option, + pub command: Command, - /// `cargo` caching is disabled by default, this flag enables it back. - #[arg(long="enable-cargo-cache", action=clap::builder::ArgAction::SetTrue)] + /// `cargo` caching is enable by default, this flag disables it. + #[arg(long="disable-cargo-cache", action=clap::builder::ArgAction::SetFalse)] pub force_cargo_build: ForceCargoBuild, /// Apply the command to every local package of the dependency closure. By @@ -421,31 +435,40 @@ pub struct Options { /// options like `-C -p ;`). #[arg(long = "deps")] pub deps: bool, + + /// By default, hax uses `$CARGO_TARGET_DIR/hax` as target folder, + /// to avoid recompilation when working both with `cargo hax` and + /// `cargo build` (or, e.g. `rust-analyzer`). This option disables + /// this behavior. + #[arg(long)] + pub no_custom_target_directory: bool, + + /// Diagnostic format. Sets `cargo`'s `--message-format` as well, + /// if not present. + #[arg(long, default_value = "human")] + pub message_format: MessageFormat, } -impl NormalizePaths for ExporterCommand { - fn normalize_paths(&mut self) { - use ExporterCommand::*; - match self { - JSON { output_file, .. } => output_file.normalize_paths(), - _ => (), - } - } +#[derive_group(Serializers)] +#[derive(JsonSchema, ValueEnum, Debug, Clone, Copy, Eq, PartialEq)] +pub enum MessageFormat { + Human, + Json, } impl NormalizePaths for Command { fn normalize_paths(&mut self) { + use Command::*; match self { - Command::ExporterCommand(cmd) => cmd.normalize_paths(), + JSON { output_file, .. } => output_file.normalize_paths(), _ => (), } } } + impl NormalizePaths for Options { fn normalize_paths(&mut self) { - if let Some(c) = &mut self.command { - c.normalize_paths() - } + self.command.normalize_paths() } } diff --git a/hax-types/src/diagnostics/message.rs b/hax-types/src/diagnostics/message.rs new file mode 100644 index 000000000..0aff7720c --- /dev/null +++ b/hax-types/src/diagnostics/message.rs @@ -0,0 +1,40 @@ +use crate::cli_options::Backend; +use crate::prelude::*; + +#[derive_group(Serializers)] +#[derive(Debug, Clone, JsonSchema)] +#[repr(u8)] +pub enum HaxMessage { + Diagnostic { + diagnostic: super::Diagnostics, + working_dir: PathBuf, + } = 254, + EngineNotFound { + is_opam_setup_correctly: bool, + } = 0, + ProducedFile { + path: PathBuf, + wrote: bool, + } = 1, + HaxEngineFailure { + exit_code: i32, + } = 2, + CargoBuildFailure = 3, + WarnExperimentalBackend { + backend: Backend, + } = 4, +} + +impl HaxMessage { + // https://doc.rust-lang.org/reference/items/enumerations.html#pointer-casting + pub fn discriminant(&self) -> u16 { + unsafe { *(self as *const Self as *const u16) } + } + + pub fn code(&self) -> String { + match self { + HaxMessage::Diagnostic { diagnostic, .. } => diagnostic.kind.code(), + _ => format!("CARGOHAX{:0>4}", self.discriminant()), + } + } +} diff --git a/frontend/diagnostics/src/lib.rs b/hax-types/src/diagnostics/mod.rs similarity index 69% rename from frontend/diagnostics/src/lib.rs rename to hax-types/src/diagnostics/mod.rs index 59e4892bf..d9e57b492 100644 --- a/frontend/diagnostics/src/lib.rs +++ b/hax-types/src/diagnostics/mod.rs @@ -1,77 +1,18 @@ -#![feature(rustc_private)] - -extern crate rustc_driver; -extern crate rustc_error_messages; -extern crate rustc_errors; -extern crate rustc_session; -extern crate rustc_span; - +use crate::prelude::*; use colored::Colorize; -use rustc_error_messages::MultiSpan; -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; - -pub trait SessionExtTrait { - fn span_hax_err + Clone>(&self, diag: Diagnostics); -} -impl SessionExtTrait for rustc_session::Session { - fn span_hax_err + Clone>(&self, diag: Diagnostics) { - let span: MultiSpan = diag.span.clone().into(); - let diag = diag.set_span(span.clone()); - self.span_err_with_code( - span, - format!("{}", diag), - rustc_errors::DiagnosticId::Error(diag.kind.code().into()), - ); - } -} -pub mod error; +pub mod message; +pub mod report; -#[derive(Debug, Clone, JsonSchema, Serialize, Deserialize)] -pub struct Diagnostics { +#[derive_group(Serializers)] +#[derive(Debug, Clone, JsonSchema)] +pub struct Diagnostics { pub kind: Kind, - pub span: S, + pub span: Vec, pub context: String, } -impl Diagnostics { - pub fn set_span(&self, span: T) -> Diagnostics { - Diagnostics { - kind: self.kind.clone(), - context: self.context.clone(), - span, - } - } -} -impl + Clone> Diagnostics { - pub fn convert( - &self, - // exhaustive list of mapping from spans of type S to spans of type T - mapping: &Vec<(S, T)>, - ) -> Diagnostics> - where - for<'b> &'b S: PartialEq, - { - self.set_span( - self.span - .clone() - .into_iter() - .map(|span| { - mapping - .iter() - .filter(|(candidate, _)| candidate == &span) - .map(|(_, span)| span) - .max() - }) - .flatten() - .cloned() - .collect(), - ) - } -} - -impl std::fmt::Display for Diagnostics { +impl std::fmt::Display for Diagnostics { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "({}) ", self.context)?; match &self.kind { @@ -128,7 +69,8 @@ impl std::fmt::Display for Diagnostics { } } -#[derive(Debug, Clone, JsonSchema, Serialize, Deserialize)] +#[derive_group(Serializers)] +#[derive(Debug, Clone, JsonSchema)] #[repr(u16)] pub enum Kind { /// Unsafe code is not supported diff --git a/hax-types/src/diagnostics/report.rs b/hax-types/src/diagnostics/report.rs new file mode 100644 index 000000000..3faba540d --- /dev/null +++ b/hax-types/src/diagnostics/report.rs @@ -0,0 +1,94 @@ +use super::Diagnostics; +use annotate_snippets::*; +use std::collections::HashMap; +use std::path::{Path, PathBuf}; +use std::rc::Rc; + +/// A context for reporting diagnostics +#[derive(Clone, Debug, Default)] +pub struct ReportCtx { + files: HashMap>, +} + +/// Translates a line and column position into an absolute offset +fn compute_offset(src: &str, mut line: usize, col: usize) -> usize { + let mut chars = src.chars().enumerate(); + while line > 1 { + while let Some((_offset, ch)) = chars.next() { + if ch == '\n' { + break; + } + } + line -= 1; + } + let offset = chars + .clone() + .next() + .map(|(offset, _ch)| offset) + .unwrap_or(0); + let are_col_first_chars_blank = chars + .take(col) + .all(|(_offset, ch)| matches!(ch, ' ' | '\t')); + if are_col_first_chars_blank { + offset + } else { + offset + col + } +} + +impl ReportCtx { + /// Read the contents of a file. The result is cached. + fn file_contents<'a>(&'a mut self, path: PathBuf) -> Rc { + self.files + .entry(path.clone()) + .or_insert_with(|| { + let s = + std::fs::read_to_string(&path).expect(&format!("Unable to read file {path:?}")); + Rc::new(s) + }) + .clone() + } +} + +impl Diagnostics { + /// Converts a `Diagnostics` to a `annotate_snippets::Message`, + /// which can be accessed via `then`, a callback function. + pub fn with_message FnMut(Message<'a>) -> R>( + &self, + report_ctx: &mut ReportCtx, + working_dir: &Path, + level: Level, + mut then: F, + ) -> R { + let mut snippets_data = vec![]; + + for span in &self.span { + if let Some(path) = span.filename.to_path() { + let source = { + let mut path = path.to_path_buf(); + if path.is_relative() { + path = working_dir.join(&path); + }; + report_ctx.file_contents(path) + }; + let start = compute_offset(&source, span.lo.line, span.lo.col); + let end = compute_offset(&source, span.hi.line, span.hi.col); + let origin = format!("{}", path.display()); + snippets_data.push((source, origin, span.lo.line, start..end)); + }; + } + + let title = format!("[{}] {self}", self.kind.code()); + let message = level.title(&title).snippets(snippets_data.iter().map( + |(source, origin, line, range)| { + Snippet::source(source) + .line_start(*line) + .origin(&origin) + .fold(true) + .annotation(level.span(range.clone())) + }, + )); + + then(message) + } +} diff --git a/hax-types/src/driver_api.rs b/hax-types/src/driver_api.rs new file mode 100644 index 000000000..13fa11412 --- /dev/null +++ b/hax-types/src/driver_api.rs @@ -0,0 +1,82 @@ +use crate::prelude::*; + +pub const HAX_DRIVER_STDERR_PREFIX: &str = "::hax-driver::"; + +#[derive_group(Serializers)] +#[derive(Debug, Clone)] +pub struct EmitHaxMetaMessage { + pub working_dir: PathBuf, + pub manifest_dir: PathBuf, + pub path: PathBuf, +} +#[derive_group(Serializers)] +#[derive(Debug, Clone)] +pub enum HaxDriverMessage { + EmitHaxMeta(EmitHaxMetaMessage), +} + +#[derive_group(Serializers)] +#[derive(Debug, Clone)] +pub struct HaxMeta { + pub crate_name: String, + pub cg_metadata: String, + pub externs: Vec, + pub items: Vec>, + pub impl_infos: Vec<( + hax_frontend_exporter::DefId, + hax_frontend_exporter::ImplInfos, + )>, + pub def_ids: Vec, +} + +impl HaxMeta +where + Body: bincode::Encode + bincode::Decode, +{ + pub fn write(self, write: &mut impl std::io::Write) { + let mut write = zstd::stream::write::Encoder::new(write, 0).unwrap(); + bincode::encode_into_std_write(self, &mut write, bincode::config::standard()).unwrap(); + write.finish().unwrap(); + } + pub fn read(reader: impl std::io::Read) -> Self { + let reader = zstd::stream::read::Decoder::new(reader).unwrap(); + let reader = std::io::BufReader::new(reader); + bincode::decode_from_reader(reader, bincode::config::standard()).unwrap() + } +} + +#[macro_export] +macro_rules! with_kind_type { + ($kind:expr, <$t:ident>|| $body:expr) => {{ + mod from { + pub use hax_types::cli_options::ExportBodyKind::{MirBuilt as MB, Thir as T}; + } + mod to { + pub type T = hax_frontend_exporter::ThirBody; + pub type MB = hax_frontend_exporter::MirBody; + } + let mut kind: Vec<::hax_types::cli_options::ExportBodyKind> = $kind; + kind.sort(); + kind.dedup(); + match kind.as_slice() { + [from::MB] => { + type $t = to::MB; + $body + } + [from::T] => { + type $t = to::T; + $body + } + [from::T, from::MB] => { + type $t = (to::MB, to::T); + $body + } + [] => { + type $t = (); + $body + } + _ => panic!("Unsupported kind {:#?}", kind), + } + }}; +} +pub use with_kind_type; diff --git a/hax-types/src/engine_api.rs b/hax-types/src/engine_api.rs new file mode 100644 index 000000000..1ea02b356 --- /dev/null +++ b/hax-types/src/engine_api.rs @@ -0,0 +1,65 @@ +use crate::cli_options::*; +use crate::prelude::*; + +type ThirBody = hax_frontend_exporter::ThirBody; + +#[derive_group(Serializers)] +#[derive(JsonSchema, Debug, Clone)] +pub struct EngineOptions { + pub backend: BackendOptions, + pub input: Vec>, + pub impl_infos: Vec<( + hax_frontend_exporter::DefId, + hax_frontend_exporter::ImplInfos, + )>, +} + +#[derive_group(Serializers)] +#[derive(JsonSchema, Debug, Clone)] +pub struct File { + pub path: String, + pub contents: String, +} + +#[derive_group(Serializers)] +#[derive(JsonSchema, Debug, Clone)] +pub struct Output { + pub diagnostics: Vec, + pub files: Vec, + pub debug_json: Option, +} + +pub mod protocol { + use super::*; + #[derive_group(Serializers)] + #[derive(JsonSchema, Debug, Clone)] + pub enum FromEngine { + Diagnostic(crate::diagnostics::Diagnostics), + File(File), + PrettyPrintDiagnostic(crate::diagnostics::Diagnostics), + PrettyPrintRust(String), + DebugString(String), + Exit, + Ping, + } + #[derive_group(Serializers)] + #[derive(JsonSchema, Debug, Clone)] + pub enum ToEngine { + PrettyPrintedDiagnostic(String), + PrettyPrintedRust(Result), + Pong, + } +} + +// This is located here for dependency reason, but this is not related +// to the engine (yet?). +#[derive_group(Serializers)] +#[derive(JsonSchema, Debug, Clone)] +pub struct WithDefIds { + pub def_ids: Vec, + pub impl_infos: Vec<( + hax_frontend_exporter::DefId, + hax_frontend_exporter::ImplInfos, + )>, + pub items: Vec>, +} diff --git a/hax-types/src/lib.rs b/hax-types/src/lib.rs new file mode 100644 index 000000000..ab974d41b --- /dev/null +++ b/hax-types/src/lib.rs @@ -0,0 +1,27 @@ +//! This crate contains the type definitions that are used to communicate between: +//! - the command line (the `cargo-hax` binary); +//! - the custom rustc driver; +//! - the hax engine (the `hax-engine` binary). +//! +//! Those three component send and receive messages in JSON or CBOR on +//! stdin and stdout. + +pub(crate) mod prelude; + +/// The CLI options for `cargo-hax`. The types defines in this module +/// are also used by the driver and the engine. +pub mod cli_options; + +/// Type to represent errors, mainly in `hax-engine`. The engine +/// doesn't do any reporting itself: it only sends JSON to its stdout, +/// and `cargo-hax` takes care of reporting everything in a rustc +/// style. +pub mod diagnostics; + +/// The types used to communicate between `cargo-hax` and the custom +/// driver. +pub mod driver_api; + +/// The types used to communicate between `cargo-hax` and +/// `hax-engine`. +pub mod engine_api; diff --git a/hax-types/src/prelude.rs b/hax-types/src/prelude.rs new file mode 100644 index 000000000..79105a5b3 --- /dev/null +++ b/hax-types/src/prelude.rs @@ -0,0 +1,3 @@ +pub(crate) use hax_adt_into::derive_group; +pub use schemars::JsonSchema; +pub use std::path::{Path, PathBuf}; diff --git a/logo.svg b/logo.svg new file mode 100644 index 000000000..38f1960a1 --- /dev/null +++ b/logo.svg @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + diff --git a/proof-libs/fstar/core/Core.Array.fst b/proof-libs/fstar/core/Core.Array.fst index c17a58262..44f48c19a 100644 --- a/proof-libs/fstar/core/Core.Array.fst +++ b/proof-libs/fstar/core/Core.Array.fst @@ -3,8 +3,10 @@ open Rust_primitives type t_TryFromSliceError = | TryFromSliceError -let impl_23__map #a #b n (arr: t_Array a n) (f: a -> b): t_Array b n +let impl_23__map #a n #b (arr: t_Array a n) (f: a -> b): t_Array b n = map_array arr f let impl_23__as_slice #a len (arr: t_Array a len): t_Slice a = arr +let from_fn #a len (f: usize -> a): t_Array a len = admit() + diff --git a/proof-libs/fstar/core/Core.Core_arch.Arm_shared.Neon.fsti b/proof-libs/fstar/core/Core.Core_arch.Arm_shared.Neon.fsti index 5772fa15c..08219c554 100644 --- a/proof-libs/fstar/core/Core.Core_arch.Arm_shared.Neon.fsti +++ b/proof-libs/fstar/core/Core.Core_arch.Arm_shared.Neon.fsti @@ -1,6 +1,7 @@ module Core.Core_arch.Arm_shared.Neon val t_int16x4_t:Type0 +val t_int16x8_t:Type0 val t_int32x2_t:Type0 val t_int32x4_t:Type0 val t_int64x2_t:Type0 diff --git a/proof-libs/fstar/core/Core.Core_arch.X86.fsti b/proof-libs/fstar/core/Core.Core_arch.X86.fsti index 6cae37564..5056e0e34 100644 --- a/proof-libs/fstar/core/Core.Core_arch.X86.fsti +++ b/proof-libs/fstar/core/Core.Core_arch.X86.fsti @@ -1,3 +1,5 @@ module Core.Core_arch.X86 +val t____m128i:Type0 + val t____m256i:Type0 diff --git a/proof-libs/fstar/core/Core.Default.fsti b/proof-libs/fstar/core/Core.Default.fsti new file mode 100644 index 000000000..406cc0774 --- /dev/null +++ b/proof-libs/fstar/core/Core.Default.fsti @@ -0,0 +1,5 @@ +module Core.Default + +class t_Default (t: Type0) = { + v_default: unit -> t; +} diff --git a/proof-libs/fstar/core/Core.Hint.fsti b/proof-libs/fstar/core/Core.Hint.fsti new file mode 100644 index 000000000..ad1d9e6b6 --- /dev/null +++ b/proof-libs/fstar/core/Core.Hint.fsti @@ -0,0 +1,3 @@ +module Core.Hint + +val black_box: #a:Type0 -> x:a -> y:a{y == x} \ No newline at end of file diff --git a/proof-libs/fstar/core/Core.Num.fsti b/proof-libs/fstar/core/Core.Num.fsti index e196b0ced..0f436ec05 100644 --- a/proof-libs/fstar/core/Core.Num.fsti +++ b/proof-libs/fstar/core/Core.Num.fsti @@ -8,6 +8,10 @@ val impl__u16__to_be_bytes: u16 -> t_Array u8 (sz 2) let impl__i32__wrapping_add: i32 -> i32 -> i32 = add_mod let impl__i32__abs (a:i32{minint i32_inttype < v a}) : i32 = abs_int a +let impl__i16__wrapping_add: i16 -> i16 -> i16 = add_mod +let impl__i16__wrapping_sub: i16 -> i16 -> i16 = sub_mod +let impl__i16__wrapping_mul: i16 -> i16 -> i16 = mul_mod + let impl__u32__wrapping_add: u32 -> u32 -> u32 = add_mod val impl__u32__rotate_left: u32 -> u32 -> u32 val impl__u32__from_le_bytes: t_Array u8 (sz 4) -> u32 @@ -38,10 +42,63 @@ val impl__u16__pow (base: u16) (exponent: u32): result : u16 {v base == 2 /\ v e val impl__u32__pow (base: u32) (exponent: u32): result : u32 {v base == 2 /\ v exponent <= 16 ==> result == mk_int #Lib.IntTypes.U32 (pow2 (v exponent))} val impl__u64__pow: u64 -> u32 -> u64 val impl__u128__pow: u128 -> u32 -> u128 +val impl__i16__pow (base: i16) (exponent: u32): result: i16 {v base == 2 /\ v exponent < 15 ==> (Math.Lemmas.pow2_lt_compat 15 (v exponent); result == mk_int #Lib.IntTypes.S16 (pow2 (v exponent)))} val impl__i32__pow (base: i32) (exponent: u32): result: i32 {v base == 2 /\ v exponent <= 16 ==> result == mk_int #Lib.IntTypes.S32 (pow2 (v exponent))} +val impl__u8__count_ones: u8 -> r:u32{v r <= 8} + val impl__u8__from_str_radix: string -> u32 -> Core.Result.t_Result u8 Core.Num.Error.t_ParseIntError val impl__usize__ilog2: i32 -> u32 val impl__usize__leading_zeros: usize -> u32 +open Core.Ops.Arith +unfold instance add_assign_num_refined_refined t ($phi1 $phi2: int_t t -> bool) + : t_AddAssign (x: int_t t {phi1 x}) (y: int_t t {phi2 y}) = { + f_add_assign_pre = (fun (x: int_t t {phi1 x}) (y: int_t t {phi2 y}) -> phi1 (x +. y)); + f_add_assign_post = (fun x y r -> x +. y = r); + f_add_assign = (fun x y -> x +. y); + } +unfold instance add_assign_num_lhs_refined t ($phi1: int_t t -> bool) + : t_AddAssign (x: int_t t {phi1 x}) (y: int_t t) = { + f_add_assign_pre = (fun (x: int_t t {phi1 x}) (y: int_t t) -> phi1 (x +. y)); + f_add_assign_post = (fun x y r -> x +. y = r); + f_add_assign = (fun x y -> x +. y); + } +unfold instance add_assign_num_rhs_refined t ($phi1: int_t t -> bool) + : t_AddAssign (x: int_t t) (y: int_t t {phi1 y}) = { + f_add_assign_pre = (fun (x: int_t t) (y: int_t t {phi1 y}) -> true); + f_add_assign_post = (fun x y r -> x +. y = r); + f_add_assign = (fun x y -> x +. y); + } +unfold instance add_assign_num t + : t_AddAssign (x: int_t t) (y: int_t t) = { + f_add_assign_pre = (fun (x: int_t t) (y: int_t t) -> true); + f_add_assign_post = (fun x y r -> x +. y = r); + f_add_assign = (fun x y -> x +. y); + } + +unfold instance sub_assign_num_refined_refined t ($phi1 $phi2: int_t t -> bool) + : t_SubAssign (x: int_t t {phi1 x}) (y: int_t t {phi2 y}) = { + f_sub_assign_pre = (fun (x: int_t t {phi1 x}) (y: int_t t {phi2 y}) -> phi1 (x -. y)); + f_sub_assign_post = (fun x y r -> x -. y = r); + f_sub_assign = (fun x y -> x -. y); + } +unfold instance sub_assign_num_lhs_refined t ($phi1: int_t t -> bool) + : t_SubAssign (x: int_t t {phi1 x}) (y: int_t t) = { + f_sub_assign_pre = (fun (x: int_t t {phi1 x}) (y: int_t t) -> phi1 (x -. y)); + f_sub_assign_post = (fun x y r -> x -. y = r); + f_sub_assign = (fun x y -> x -. y); + } +unfold instance sub_assign_num_rhs_refined t ($phi1: int_t t -> bool) + : t_SubAssign (x: int_t t) (y: int_t t {phi1 y}) = { + f_sub_assign_pre = (fun (x: int_t t) (y: int_t t {phi1 y}) -> true); + f_sub_assign_post = (fun x y r -> x -. y = r); + f_sub_assign = (fun x y -> x -. y); + } +unfold instance sub_assign_num t + : t_SubAssign (x: int_t t) (y: int_t t) = { + f_sub_assign_pre = (fun (x: int_t t) (y: int_t t) -> true); + f_sub_assign_post = (fun x y r -> x -. y = r); + f_sub_assign = (fun x y -> x -. y); + } diff --git a/proof-libs/fstar/core/Core.Ops.Arith.fsti b/proof-libs/fstar/core/Core.Ops.Arith.fsti index 1df19aed9..a3d75535f 100644 --- a/proof-libs/fstar/core/Core.Ops.Arith.fsti +++ b/proof-libs/fstar/core/Core.Ops.Arith.fsti @@ -33,3 +33,16 @@ class t_Div self rhs = { f_div_post: self -> rhs -> f_Output -> bool; f_div: x:self -> y:rhs -> Pure f_Output (f_div_pre x y) (fun r -> f_div_post x y r); } + +class t_AddAssign self rhs = { + f_add_assign_pre: self -> rhs -> bool; + f_add_assign_post: self -> rhs -> self -> bool; + f_add_assign: x:self -> y:rhs -> Pure self (f_add_assign_pre x y) (fun r -> f_add_assign_post x y r); +} + +class t_SubAssign self rhs = { + f_sub_assign_pre: self -> rhs -> bool; + f_sub_assign_post: self -> rhs -> self -> bool; + f_sub_assign: x:self -> y:rhs -> Pure self (f_sub_assign_pre x y) (fun r -> f_sub_assign_post x y r); +} + diff --git a/proof-libs/fstar/core/Core.Ops.Deref.fst b/proof-libs/fstar/core/Core.Ops.Deref.fst index c99ea9e6d..15b5565ca 100644 --- a/proof-libs/fstar/core/Core.Ops.Deref.fst +++ b/proof-libs/fstar/core/Core.Ops.Deref.fst @@ -1,3 +1,12 @@ module Core.Ops.Deref -let f_deref = id +class t_Deref (t_Self: Type0) = { + f_Target: Type0; + f_deref: t_Self -> f_Target; +} + +unfold +instance identity_Deref t_Self: t_Deref t_Self = { + f_Target = t_Self; + f_deref = (fun x -> x); +} diff --git a/proof-libs/fstar/rust_primitives/Rust_primitives.BitVectors.fst b/proof-libs/fstar/rust_primitives/Rust_primitives.BitVectors.fst index b6477f73b..5bb914e52 100644 --- a/proof-libs/fstar/rust_primitives/Rust_primitives.BitVectors.fst +++ b/proof-libs/fstar/rust_primitives/Rust_primitives.BitVectors.fst @@ -22,6 +22,10 @@ let pow2_minus_one_mod_lemma2 (n: nat) (m: nat {n <= m}) = Math.Lemmas.pow2_le_compat m n; Math.Lemmas.small_div (pow2 n - 1) (pow2 m) +let bit_vec_to_int_t #t (d: num_bits t) (bv: bit_vec d) = admit () + +let bit_vec_to_int_t_lemma #t (d: num_bits t) (bv: bit_vec d) i = admit () + let bit_vec_to_int_t_array d bv = admit () // see issue #423 let bit_vec_to_nat_array d bv = admit () // see issue #423 @@ -30,26 +34,33 @@ let get_bit_pow2_minus_one #t n nth if v nth < n then pow2_minus_one_mod_lemma1 n (v nth) else pow2_minus_one_mod_lemma2 n (v nth) +let mask_inv_opt_in_range #t (mask: int_t t {Some? (mask_inv_opt (v mask))}) + : Lemma (range (Some?.v (mask_inv_opt (v mask))) t) + [SMTPat (mask_inv_opt (v mask))] + = let n = (Some?.v (mask_inv_opt (v mask))) in + assert (pow2 n - 1 == v mask) + let get_bit_pow2_minus_one_i32 x nth = let n = Some?.v (mask_inv_opt x) in - assume (pow2 n - 1 == x); // see issue #423 mk_int_equiv_lemma #i32_inttype x; get_bit_pow2_minus_one #i32_inttype n nth +let get_bit_pow2_minus_one_i16 x nth + = let n = Some?.v (mask_inv_opt x) in + mk_int_equiv_lemma #i16_inttype x; + get_bit_pow2_minus_one #i16_inttype n nth + let get_bit_pow2_minus_one_u32 x nth = let n = Some?.v (mask_inv_opt x) in - assume (pow2 n - 1 == x); // see issue #423 mk_int_equiv_lemma #u32_inttype x; get_bit_pow2_minus_one #u32_inttype n nth let get_bit_pow2_minus_one_u16 x nth = let n = Some?.v (mask_inv_opt x) in - assume (pow2 n - 1 == x); // see issue #423 mk_int_equiv_lemma #u16_inttype x; get_bit_pow2_minus_one #u16_inttype n nth let get_bit_pow2_minus_one_u8 t x nth = let n = Some?.v (mask_inv_opt x) in - assume (pow2 n - 1 == x); // see issue #423 mk_int_equiv_lemma #u8_inttype x; get_bit_pow2_minus_one #u8_inttype n nth diff --git a/proof-libs/fstar/rust_primitives/Rust_primitives.BitVectors.fsti b/proof-libs/fstar/rust_primitives/Rust_primitives.BitVectors.fsti index 8331d55b6..b8bf183d0 100644 --- a/proof-libs/fstar/rust_primitives/Rust_primitives.BitVectors.fsti +++ b/proof-libs/fstar/rust_primitives/Rust_primitives.BitVectors.fsti @@ -58,6 +58,15 @@ let bit_vec_of_nat_array (#len: usize) (fun i -> get_bit_nat (Seq.index arr (i / d)) (i % d)) #pop-options +/// Transforms a bit vector to an integer +val bit_vec_to_int_t #t (d: num_bits t) (bv: bit_vec d): int_t t + +/// `bit_vec_to_int_t` and `get_bit` are (modulo usize) inverse +val bit_vec_to_int_t_lemma + #t (d: num_bits t) (bv: bit_vec d) + i + : Lemma (get_bit (bit_vec_to_int_t d bv) (sz i) == bv i) + /// Transforms a bit vector into an array of integers val bit_vec_to_int_t_array #t (#len: usize) (d: num_bits t) (bv: bit_vec (v len * d)) : Pure (t_Array (int_t t) len) @@ -103,6 +112,14 @@ val get_bit_pow2_minus_one_i32 == (if v nth < Some?.v (mask_inv_opt x) then 1 else 0)) [SMTPat (get_bit (FStar.Int32.int_to_t x) nth)] +/// Specialized `get_bit_pow2_minus_one` lemmas with SMT patterns +/// targetting machine integer literals of type `i16` +val get_bit_pow2_minus_one_i16 + (x: int {x < pow2 15 /\ Some? (mask_inv_opt x)}) (nth: usize {v nth < 16}) + : Lemma ( get_bit (FStar.Int16.int_to_t x) nth + == (if v nth < Some?.v (mask_inv_opt x) then 1 else 0)) + [SMTPat (get_bit (FStar.Int16.int_to_t x) nth)] + /// Specialized `get_bit_pow2_minus_one` lemmas with SMT patterns /// targetting machine integer literals of type `u32` val get_bit_pow2_minus_one_u32 diff --git a/proof-libs/fstar/rust_primitives/Rust_primitives.Hax.Folds.fsti b/proof-libs/fstar/rust_primitives/Rust_primitives.Hax.Folds.fsti new file mode 100644 index 000000000..4b495b6d1 --- /dev/null +++ b/proof-libs/fstar/rust_primitives/Rust_primitives.Hax.Folds.fsti @@ -0,0 +1,109 @@ +module Rust_primitives.Hax.Folds + +open Rust_primitives +open Core.Ops.Range +open FStar.Mul + +(**** `s.chunks_exact(chunk_size).enumerate()` *) +/// Predicate that asserts a slice `s_chunk` is exactly the nth chunk +/// of the sequence `s` +let nth_chunk_of #t + (s: Seq.seq t) + (s_chunk: Seq.seq t {Seq.length s_chunk > 0}) + (chunk_nth: nat {chunk_nth < Seq.length s / Seq.length s_chunk}) + = Seq.slice s (Seq.length s_chunk * chunk_nth) (Seq.length s_chunk * (chunk_nth + 1)) + == s_chunk + +/// Fold function that is generated for `for` loops iterating on +/// `s.chunks_exact(chunk_size).enumerate()`-like iterators +val fold_enumerated_chunked_slice + (#t: Type0) (#acc_t: Type0) + (chunk_size: usize {v chunk_size > 0}) + (s: t_Slice t) + (inv: acc_t -> (i:usize{v i <= Seq.length s / v chunk_size}) -> Type0) + (init: acc_t {inv init (sz 0)}) + (f: ( acc:acc_t + -> item:(usize & t_Slice t) { + let (i, s_chunk) = item in + v i < Seq.length s / v chunk_size + /\ length s_chunk == chunk_size + /\ nth_chunk_of s s_chunk (v i) + /\ inv acc i + } + -> acc':acc_t { + inv acc' (fst item +! sz 1) + } + ) + ) + : result: acc_t {inv result (mk_int (Seq.length s / v chunk_size))} + +(**** `s.enumerate()` *) +/// Fold function that is generated for `for` loops iterating on +/// `s.enumerate()`-like iterators +val fold_enumerated_slice + (#t: Type0) (#acc_t: Type0) + (s: t_Slice t) + (inv: acc_t -> (i:usize{v i <= v (length s)}) -> Type0) + (init: acc_t {inv init (sz 0)}) + (f: (acc:acc_t -> i:(usize & t) {v (fst i) < v (length s) /\ inv acc (fst i)} + -> acc':acc_t {v (fst i) < v (length s) /\ inv acc' (fst i)})) + : result: acc_t {inv result (length s)} + +(**** `(start..end_).step_by(step)` *) +unfold let fold_range_step_by_wf_index (#u: Lib.IntTypes.inttype) + (start: int_t u) (end_: int_t u) + (step: usize {v step > 0}) (strict: bool) (i: int) + = v start <= v end_ ==> ( i >= v start + /\ (if strict then i < v end_ else i <= v end_ + v step)) + // /\ i % v step == v start % v step + +#push-options "--z3rlimit 80" +unfold let fold_range_step_by_upper_bound (#u: Lib.IntTypes.inttype) + (start: int_t u) (end_: int_t u) + (step: usize {v step > 0}) + : end':int {fold_range_step_by_wf_index start end_ step false end'} + = if v end_ <= v start + then v end_ + else + let range: nat = v end_ - v start in + let k: nat = range / v step in + let end' = v start + k * v step in + FStar.Math.Lemmas.division_propriety range (v step); + end' +#pop-options + +/// Fold function that is generated for `for` loops iterating on +/// `s.enumerate()`-like iterators +val fold_range_step_by + (#acc_t: Type0) (#u: Lib.IntTypes.inttype) + (start: int_t u) + (end_: int_t u) + (step: usize {v step > 0 /\ range (v end_ + v step) u}) + (inv: acc_t -> (i:int_t u{fold_range_step_by_wf_index start end_ step false (v i)}) -> Type0) + (init: acc_t {inv init start}) + (f: (acc:acc_t -> i:int_t u {v i < v end_ /\ fold_range_step_by_wf_index start end_ step true (v i) /\ inv acc i} + -> acc':acc_t {(inv acc' (mk_int (v i + v step)))})) + : result: acc_t {inv result (mk_int (fold_range_step_by_upper_bound start end_ step))} + +(**** `start..end_` *) +unfold let fold_range_wf_index (#u: Lib.IntTypes.inttype) + (start: int_t u) (end_: int_t u) + (strict: bool) (i: int) + = v start <= v end_ + ==> ( i >= v start + /\ (if strict then i < v end_ else i <= v end_)) + +let rec fold_range + (#acc_t: Type0) (#u: Lib.IntTypes.inttype) + (start: int_t u) + (end_: int_t u) + (inv: acc_t -> (i:int_t u{fold_range_wf_index start end_ false (v i)}) -> Type0) + (init: acc_t {inv init start}) + (f: (acc:acc_t -> i:int_t u {v i <= v end_ /\ fold_range_wf_index start end_ true (v i) /\ inv acc i} + -> acc':acc_t {(inv acc' (mk_int (v i + 1)))})) + : Tot (result: acc_t {inv result (if v start > v end_ then start else end_)}) + (decreases v end_ - v start) + = if v start < v end_ + then fold_range (start +! mk_int 1) end_ inv (f init start) f + else init + diff --git a/proof-libs/fstar/rust_primitives/Rust_primitives.Hax.Monomorphized_update_at.fsti b/proof-libs/fstar/rust_primitives/Rust_primitives.Hax.Monomorphized_update_at.fsti index b884e1cf1..dd335cf4e 100644 --- a/proof-libs/fstar/rust_primitives/Rust_primitives.Hax.Monomorphized_update_at.fsti +++ b/proof-libs/fstar/rust_primitives/Rust_primitives.Hax.Monomorphized_update_at.fsti @@ -7,14 +7,16 @@ open Rust_primitives open Rust_primitives.Hax open Core.Ops.Range -val update_at_usize +let update_at_usize (#t: Type0) (s: t_Slice t) - (i: usize) + (i: usize {v i < Seq.length s}) (x: t) - : Pure (t_Array t (length s)) - (requires (v i < Seq.length s)) - (ensures (fun res -> res == Seq.upd s (v i) x)) + : t_Array t (length s) + = Seq.upd #t s (v i) x + // : Pure (t_Array t (length s)) + // (requires (v i < Seq.length s)) + // (ensures (fun res -> res == Seq.upd s (v i) x)) val update_at_range #n (#t: Type0) diff --git a/proof-libs/fstar/rust_primitives/Rust_primitives.Hax.fst b/proof-libs/fstar/rust_primitives/Rust_primitives.Hax.fst index 2ae166f32..f009fd4c0 100644 --- a/proof-libs/fstar/rust_primitives/Rust_primitives.Hax.fst +++ b/proof-libs/fstar/rust_primitives/Rust_primitives.Hax.fst @@ -50,7 +50,8 @@ instance update_at_tc_array t l n: update_at_tc (t_Array t l) (int_t n) = { let (.[]<-) #self #idx {| update_at_tc self idx |} (s: self) (i: idx {f_index_pre s i}) = update_at s i -let array_of_list (#t:Type) +unfold let array_of_list (#t:Type) (n: nat {n < maxint Lib.IntTypes.U16}) (l: list t {FStar.List.Tot.length l == n}) - : t_Array t (sz n) = Rust_primitives.Arrays.of_list #t l + : t_Array t (sz n) + = Seq.seq_of_list l diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 7dee8050a..9d093adde 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-09-19" +channel = "nightly-2024-08-11" components = [ "rustc-dev", "llvm-tools-preview" , "rust-analysis" , "rust-src" , "rustfmt" ] diff --git a/test-harness/Cargo.toml b/test-harness/Cargo.toml index 619bbd105..e0dbfe4ca 100644 --- a/test-harness/Cargo.toml +++ b/test-harness/Cargo.toml @@ -24,4 +24,4 @@ assert_cmd = "2.0" insta = {version = "1.29.0", features = ["filters", "toml"]} serde = { version = "1.0", features = ["derive"] } regex = "1" -hax-cli-options-engine.workspace = true +hax-types.workspace = true diff --git a/test-harness/src/harness.rs b/test-harness/src/harness.rs index 453c8bf48..6d3c0db90 100644 --- a/test-harness/src/harness.rs +++ b/test-harness/src/harness.rs @@ -6,13 +6,11 @@ use std::process::{Command, Stdio}; #[derive(Clone, Debug, serde::Serialize)] pub enum TestKind { Translate { backend: String }, - Lint { linter: String }, } impl TestKind { fn as_name(&self) -> String { (match self { - TestKind::Lint { linter } => ["lint".to_string(), linter.clone()], TestKind::Translate { backend } => ["into".to_string(), backend.clone()], }) .join("-") @@ -111,7 +109,6 @@ pub struct Test { impl Test { fn as_args(&self) -> Vec { match &self.kind { - TestKind::Lint { linter } => vec!["lint".to_string(), linter.clone()], TestKind::Translate { backend } => { let mut args = vec![]; args.push("into".to_string()); @@ -187,7 +184,7 @@ impl Test { snapshot.insert( "stdout".to_string(), serde_json::from_str(&sout) - .map(|out: hax_cli_options_engine::Output| { + .map(|out: hax_types::engine_api::Output| { use serde_json::json; json!({ "diagnostics": Value::Array(out.diagnostics.into_iter().map(|diag| json!({ @@ -285,7 +282,6 @@ fn parse_hax_tests_metadata(info: TestInfo, metadata: &Value) -> Vec { info: info.clone(), kind: match a.as_str() { "into" => TestKind::Translate { backend: b }, - "lint" => TestKind::Lint { linter: b }, _ => panic!( "unexpected metadata [hax-tests.{}.{}] for package {:#?}", a, b, info @@ -302,8 +298,11 @@ fn main() { .unwrap(); let workspace_root: String = metadata.workspace_root.into(); + let mut args = libtest_mimic::Arguments::from_args(); + args.test_threads = Some(1); + libtest_mimic::run( - &libtest_mimic::Arguments::from_args(), + &args, metadata .packages .into_iter() diff --git a/test-harness/src/snapshots/toolchain__assert into-coq.snap b/test-harness/src/snapshots/toolchain__assert into-coq.snap new file mode 100644 index 000000000..fd9ff5e71 --- /dev/null +++ b/test-harness/src/snapshots/toolchain__assert into-coq.snap @@ -0,0 +1,51 @@ +--- +source: test-harness/src/harness.rs +expression: snapshot +info: + kind: + Translate: + backend: coq + info: + name: assert + manifest: assert/Cargo.toml + description: ~ + spec: + optional: false + broken: false + issue_id: ~ + positive: true + snapshot: + stderr: false + stdout: true + include_flag: ~ + backend_options: ~ +--- +exit = 0 + +[stdout] +diagnostics = [] + +[stdout.files] +"Assert.v" = ''' +(* File automatically generated by Hacspec *) +From Hacspec Require Import Hacspec_Lib MachineIntegers. +From Coq Require Import ZArith. +Import List.ListNotations. +Open Scope Z_scope. +Open Scope bool_scope. + +(*Not implemented yet? todo(item)*) + +Definition asserts (_ : unit) : unit := + let _ := assert true : unit in + let _ := assert ((@repr WORDSIZE32 1)=.?(@repr WORDSIZE32 1)) : unit in + let _ := match ((@repr WORDSIZE32 2),(@repr WORDSIZE32 2)) with + | '(left_val,right_val) => + assert (left_val=.?right_val) + end : unit in + let _ := match ((@repr WORDSIZE32 1),(@repr WORDSIZE32 2)) with + | '(left_val,right_val) => + assert (not (left_val=.?right_val)) + end : unit in + tt. +''' diff --git a/test-harness/src/snapshots/toolchain__assert into-fstar.snap b/test-harness/src/snapshots/toolchain__assert into-fstar.snap new file mode 100644 index 000000000..f74cb55a4 --- /dev/null +++ b/test-harness/src/snapshots/toolchain__assert into-fstar.snap @@ -0,0 +1,47 @@ +--- +source: test-harness/src/harness.rs +expression: snapshot +info: + kind: + Translate: + backend: fstar + info: + name: assert + manifest: assert/Cargo.toml + description: ~ + spec: + optional: false + broken: false + issue_id: ~ + positive: true + snapshot: + stderr: false + stdout: true + include_flag: ~ + backend_options: ~ +--- +exit = 0 + +[stdout] +diagnostics = [] + +[stdout.files] +"Assert.fst" = ''' +module Assert +#set-options "--fuel 0 --ifuel 1 --z3rlimit 15" +open Core +open FStar.Mul + +let asserts (_: Prims.unit) : Prims.unit = + let _:Prims.unit = Hax_lib.v_assert true in + let _:Prims.unit = Hax_lib.v_assert (1l =. 1l <: bool) in + let _:Prims.unit = + match 2l, 2l <: (i32 & i32) with + | left_val, right_val -> Hax_lib.v_assert (left_val =. right_val <: bool) + in + let _:Prims.unit = + match 1l, 2l <: (i32 & i32) with + | left_val, right_val -> Hax_lib.v_assert (~.(left_val =. right_val <: bool) <: bool) + in + () +''' diff --git a/test-harness/src/snapshots/toolchain__assert into-ssprove.snap b/test-harness/src/snapshots/toolchain__assert into-ssprove.snap new file mode 100644 index 000000000..c535a7727 --- /dev/null +++ b/test-harness/src/snapshots/toolchain__assert into-ssprove.snap @@ -0,0 +1,72 @@ +--- +source: test-harness/src/harness.rs +expression: snapshot +info: + kind: + Translate: + backend: ssprove + info: + name: assert + manifest: assert/Cargo.toml + description: ~ + spec: + optional: false + broken: false + issue_id: ~ + positive: true + snapshot: + stderr: false + stdout: true + include_flag: ~ + backend_options: ~ +--- +exit = 0 + +[stdout] +diagnostics = [] + +[stdout.files] +"Assert.v" = ''' +(* File automatically generated by Hacspec *) +Set Warnings "-notation-overridden,-ambiguous-paths". +From Crypt Require Import choice_type Package Prelude. +Import PackageNotation. +From extructures Require Import ord fset. +From mathcomp Require Import word_ssrZ word. +From Jasmin Require Import word. + +From Coq Require Import ZArith. +From Coq Require Import Strings.String. +Import List.ListNotations. +Open Scope list_scope. +Open Scope Z_scope. +Open Scope bool_scope. + +From Hacspec Require Import ChoiceEquality. +From Hacspec Require Import LocationUtility. +From Hacspec Require Import Hacspec_Lib_Comparable. +From Hacspec Require Import Hacspec_Lib_Pre. +From Hacspec Require Import Hacspec_Lib. + +Open Scope hacspec_scope. +Import choice.Choice.Exports. + +Obligation Tactic := (* try timeout 8 *) solve_ssprove_obligations. + +(*Not implemented yet? todo(item)*) + +Equations asserts {L1 : {fset Location}} {I1 : Interface} (_ : both L1 I1 'unit) : both L1 I1 'unit := + asserts _ := + letb _ := assert (ret_both (true : 'bool)) in + letb _ := assert ((ret_both (1 : int32)) =.? (ret_both (1 : int32))) in + letb _ := matchb prod_b (ret_both (2 : int32),ret_both (2 : int32)) with + | '(left_val,right_val) => + solve_lift (assert (left_val =.? right_val)) + end in + letb _ := matchb prod_b (ret_both (1 : int32),ret_both (2 : int32)) with + | '(left_val,right_val) => + solve_lift (assert (not (left_val =.? right_val))) + end in + solve_lift (ret_both (tt : 'unit)) : both L1 I1 'unit. +Fail Next Obligation. +''' diff --git a/test-harness/src/snapshots/toolchain__attribute-opaque into-fstar.snap b/test-harness/src/snapshots/toolchain__attribute-opaque into-fstar.snap index 3e5e8e8fb..2275da427 100644 --- a/test-harness/src/snapshots/toolchain__attribute-opaque into-fstar.snap +++ b/test-harness/src/snapshots/toolchain__attribute-opaque into-fstar.snap @@ -23,9 +23,7 @@ info: - +** --- exit = 0 -stderr = ''' -Compiling attribute-opaque v0.1.0 (WORKSPACE_ROOT/attribute-opaque) - Finished dev [unoptimized + debuginfo] target(s) in XXs''' +stderr = 'Finished `dev` profile [unoptimized + debuginfo] target(s) in XXs' [stdout] diagnostics = [] diff --git a/test-harness/src/snapshots/toolchain__attributes into-fstar.snap b/test-harness/src/snapshots/toolchain__attributes into-fstar.snap index eda0b67cf..6c30e8a40 100644 --- a/test-harness/src/snapshots/toolchain__attributes into-fstar.snap +++ b/test-harness/src/snapshots/toolchain__attributes into-fstar.snap @@ -26,6 +26,64 @@ exit = 0 diagnostics = [] [stdout.files] +"Attributes.Ensures_on_arity_zero_fns.fst" = ''' +module Attributes.Ensures_on_arity_zero_fns +#set-options "--fuel 0 --ifuel 1 --z3rlimit 15" +open Core +open FStar.Mul + +let basically_a_constant (_: Prims.unit) + : Prims.Pure u8 + (requires true) + (ensures + fun x -> + let x:u8 = x in + x >. 100uy) = 127uy + +let doing_nothing (_: Prims.unit) + : Prims.Pure Prims.unit + (requires true) + (ensures + fun v__x -> + let v__x:Prims.unit = v__x in + true) = () +''' +"Attributes.Inlined_code_ensures_requires.fst" = ''' +module Attributes.Inlined_code_ensures_requires +#set-options "--fuel 0 --ifuel 1 --z3rlimit 15" +open Core +open FStar.Mul + +let increment_array (v: t_Array u8 (sz 4)) + : Prims.Pure (t_Array u8 (sz 4)) + (requires forall i. FStar.Seq.index v i <. 254uy) + (ensures + fun vv_future -> + let vv_future:t_Array u8 (sz 4) = vv_future in + let future_v:t_Array u8 (sz 4) = vv_future in + forall i. FStar.Seq.index future_v i >. 0uy) = + let v:t_Array u8 (sz 4) = + Rust_primitives.Hax.Monomorphized_update_at.update_at_usize v + (sz 0) + ((v.[ sz 0 ] <: u8) +! 1uy <: u8) + in + let v:t_Array u8 (sz 4) = + Rust_primitives.Hax.Monomorphized_update_at.update_at_usize v + (sz 1) + ((v.[ sz 1 ] <: u8) +! 1uy <: u8) + in + let v:t_Array u8 (sz 4) = + Rust_primitives.Hax.Monomorphized_update_at.update_at_usize v + (sz 2) + ((v.[ sz 2 ] <: u8) +! 1uy <: u8) + in + let v:t_Array u8 (sz 4) = + Rust_primitives.Hax.Monomorphized_update_at.update_at_usize v + (sz 3) + ((v.[ sz 3 ] <: u8) +! 1uy <: u8) + in + v +''' "Attributes.Int_model.fst" = ''' module Attributes.Int_model #set-options "--fuel 0 --ifuel 1 --z3rlimit 15" @@ -44,6 +102,16 @@ unfold instance impl: Core.Ops.Arith.t_Sub t_Int t_Int = f_sub = fun (self: t_Int) (other: t_Int) -> self + other } ''' +"Attributes.Nested_refinement_elim.fst" = ''' +module Attributes.Nested_refinement_elim +#set-options "--fuel 0 --ifuel 1 --z3rlimit 15" +open Core +open FStar.Mul + +let t_DummyRefinement = x: u16{true} + +let elim_twice (x: t_DummyRefinement) : u16 = ((x <: u16) <: t_DummyRefinement) <: u16 +''' "Attributes.Newtype_pattern.fst" = ''' module Attributes.Newtype_pattern #set-options "--fuel 0 --ifuel 1 --z3rlimit 15" @@ -70,6 +138,81 @@ let impl_1 (#v_T: Type0) : Core.Ops.Index.t_Index (t_Array v_T (sz 10)) t_SafeIn f_index = fun (self: t_Array v_T (sz 10)) (index: t_SafeIndex) -> self.[ index.f_i ] } ''' +"Attributes.Pre_post_on_traits_and_impls.fst" = ''' +module Attributes.Pre_post_on_traits_and_impls +#set-options "--fuel 0 --ifuel 1 --z3rlimit 15" +open Core +open FStar.Mul + +class t_Operation (v_Self: Type0) = { + f_double_pre:x: u8 + -> pred: + Type0 + { (Rust_primitives.Hax.Int.from_machine x <: Hax_lib.Int.t_Int) <= + (127 <: Hax_lib.Int.t_Int) ==> + pred }; + f_double_post:x: u8 -> result: u8 + -> pred: + Type0 + { pred ==> + ((Rust_primitives.Hax.Int.from_machine x <: Hax_lib.Int.t_Int) * (2 <: Hax_lib.Int.t_Int) + <: + Hax_lib.Int.t_Int) = + (Rust_primitives.Hax.Int.from_machine result <: Hax_lib.Int.t_Int) }; + f_double:x0: u8 -> Prims.Pure u8 (f_double_pre x0) (fun result -> f_double_post x0 result) +} + +class t_TraitWithRequiresAndEnsures (v_Self: Type0) = { + f_method_pre:self___: v_Self -> x: u8 -> pred: Type0{x <. 100uy ==> pred}; + f_method_post:self___: v_Self -> x: u8 -> r: u8 -> pred: Type0{pred ==> r >. 88uy}; + f_method:x0: v_Self -> x1: u8 + -> Prims.Pure u8 (f_method_pre x0 x1) (fun result -> f_method_post x0 x1 result) +} + +let test + (#v_T: Type0) + (#[FStar.Tactics.Typeclasses.tcresolve ()] i1: t_TraitWithRequiresAndEnsures v_T) + (x: v_T) + : u8 = (f_method #v_T #FStar.Tactics.Typeclasses.solve x 99uy <: u8) -! 88uy + +type t_ViaAdd = | ViaAdd : t_ViaAdd + +[@@ FStar.Tactics.Typeclasses.tcinstance] +let impl: t_Operation t_ViaAdd = + { + f_double_pre + = + (fun (x: u8) -> + (Rust_primitives.Hax.Int.from_machine x <: Hax_lib.Int.t_Int) <= (127 <: Hax_lib.Int.t_Int)); + f_double_post + = + (fun (x: u8) (out: u8) -> + ((Rust_primitives.Hax.Int.from_machine x <: Hax_lib.Int.t_Int) * (2 <: Hax_lib.Int.t_Int) + <: + Hax_lib.Int.t_Int) = + (Rust_primitives.Hax.Int.from_machine out <: Hax_lib.Int.t_Int)); + f_double = fun (x: u8) -> x +! x + } + +type t_ViaMul = | ViaMul : t_ViaMul + +[@@ FStar.Tactics.Typeclasses.tcinstance] +let impl_1: t_Operation t_ViaMul = + { + f_double_pre + = + (fun (x: u8) -> + (Rust_primitives.Hax.Int.from_machine x <: Hax_lib.Int.t_Int) <= (127 <: Hax_lib.Int.t_Int)); + f_double_post + = + (fun (x: u8) (out: u8) -> + ((Rust_primitives.Hax.Int.from_machine x <: Hax_lib.Int.t_Int) * (2 <: Hax_lib.Int.t_Int) + <: + Hax_lib.Int.t_Int) = + (Rust_primitives.Hax.Int.from_machine out <: Hax_lib.Int.t_Int)); + f_double = fun (x: u8) -> x *! 2uy + } +''' "Attributes.Refined_arithmetic.fst" = ''' module Attributes.Refined_arithmetic #set-options "--fuel 0 --ifuel 1 --z3rlimit 15" @@ -173,7 +316,12 @@ let t_NoE = Alloc.String.t_String { let _, out:(Core.Str.Iter.t_Chars & bool) = Core.Iter.Traits.Iterator.f_any #Core.Str.Iter.t_Chars - (Core.Str.impl__str__chars (Core.Ops.Deref.f_deref #Alloc.String.t_String x <: string) + #FStar.Tactics.Typeclasses.solve + (Core.Str.impl__str__chars (Core.Ops.Deref.f_deref #Alloc.String.t_String + #FStar.Tactics.Typeclasses.solve + x + <: + string) <: Core.Str.Iter.t_Chars) (fun ch -> @@ -183,10 +331,7 @@ let t_NoE = ~.out } let bounded_u8 (x: t_BoundedU8 12uy 15uy) (y: t_BoundedU8 10uy 11uy) : t_BoundedU8 1uy 23uy = - (Hax_lib.f_get #(t_BoundedU8 12uy 15uy) x <: u8) +! - (Hax_lib.f_get #(t_BoundedU8 10uy 11uy) y <: u8) - <: - t_BoundedU8 1uy 23uy + (x <: u8) +! (y <: u8) <: t_BoundedU8 1uy 23uy let double (x: u8) : Prims.Pure t_Even (requires x <. 127uy) (fun _ -> Prims.l_True) = x +! x <: t_Even @@ -194,6 +339,43 @@ let double (x: u8) : Prims.Pure t_Even (requires x <. 127uy) (fun _ -> Prims.l_T let double_refine (x: u8) : Prims.Pure t_Even (requires x <. 127uy) (fun _ -> Prims.l_True) = x +! x <: t_Even ''' +"Attributes.Verifcation_status.fst" = ''' +module Attributes.Verifcation_status +#set-options "--fuel 0 --ifuel 1 --z3rlimit 15" +open Core +open FStar.Mul + +let a_panicfree_function (_: Prims.unit) + : Prims.Pure u8 + Prims.l_True + (ensures + fun x -> + let x:u8 = x in + false) = + let a:u8 = 3uy in + let b:u8 = 6uy in + let result:u8 = a +! b in + let _:Prims.unit = admit () (* Panic freedom *) in + result + +let another_panicfree_function (_: Prims.unit) + : Prims.Pure Prims.unit + Prims.l_True + (ensures + fun x -> + let x:Prims.unit = x in + false) = + let not_much:i32 = 0l in + let nothing:i32 = 0l in + let still_not_much:i32 = not_much +! nothing in + admit () (* Panic freedom *) + +#push-options "--admit_smt_queries true" + +let a_function_which_only_laxes (_: Prims.unit) : Prims.unit = Hax_lib.v_assert false + +#pop-options +''' "Attributes.fst" = ''' module Attributes #set-options "--fuel 0 --ifuel 1 --z3rlimit 15" @@ -208,6 +390,14 @@ let add3_lemma (x: u32) let inlined_code__V: u8 = 12uy +let issue_844_ (v__x: u8) + : Prims.Pure u8 + Prims.l_True + (ensures + fun v__x_future -> + let v__x_future:u8 = v__x_future in + true) = v__x + let u32_max: u32 = 90000ul unfold let some_function _ = "hello from F*" @@ -225,6 +415,19 @@ let add3 (x y z: u32) let _:Prims.unit = temp_0_ in result >. 32ul <: bool)) = (x +! y <: u32) +! z +let swap_and_mut_req_ens (x y: u32) + : Prims.Pure (u32 & u32 & u32) + (requires x <. 40ul && y <. 300ul) + (ensures + fun temp_0_ -> + let x_future, y_future, result:(u32 & u32 & u32) = temp_0_ in + x_future =. y && y_future =. x && result =. (x +! y <: u32)) = + let x0:u32 = x in + let x:u32 = y in + let y:u32 = x0 in + let hax_temp_output:u32 = x +! y in + x, y, hax_temp_output <: (u32 & u32 & u32) + type t_Foo = { f_x:u32; f_y:f_y: u32{f_y >. 3ul}; diff --git a/test-harness/src/snapshots/toolchain__dyn into-fstar.snap b/test-harness/src/snapshots/toolchain__dyn into-fstar.snap new file mode 100644 index 000000000..209e239dd --- /dev/null +++ b/test-harness/src/snapshots/toolchain__dyn into-fstar.snap @@ -0,0 +1,83 @@ +--- +source: test-harness/src/harness.rs +expression: snapshot +info: + kind: + Translate: + backend: fstar + info: + name: dyn + manifest: dyn/Cargo.toml + description: ~ + spec: + optional: false + broken: false + issue_id: ~ + positive: true + snapshot: + stderr: false + stdout: true + include_flag: ~ + backend_options: ~ +--- +exit = 0 + +[stdout] +diagnostics = [] + +[stdout.files] +"Dyn.fst" = ''' +module Dyn +#set-options "--fuel 0 --ifuel 1 --z3rlimit 15" +open Core +open FStar.Mul + +class t_Printable (v_Self: Type0) (v_S: Type0) = { + f_stringify_pre:v_Self -> Type0; + f_stringify_post:v_Self -> v_S -> Type0; + f_stringify:x0: v_Self + -> Prims.Pure v_S (f_stringify_pre x0) (fun result -> f_stringify_post x0 result) +} + +[@@ FStar.Tactics.Typeclasses.tcinstance] +let impl: t_Printable i32 Alloc.String.t_String = + { + f_stringify_pre = (fun (self: i32) -> true); + f_stringify_post = (fun (self: i32) (out: Alloc.String.t_String) -> true); + f_stringify + = + fun (self: i32) -> Alloc.String.f_to_string #i32 #FStar.Tactics.Typeclasses.solve self + } + +let print + (a: + Alloc.Boxed.t_Box (dyn 1 (fun z -> t_Printable z Alloc.String.t_String)) + Alloc.Alloc.t_Global) + : Prims.unit = + let _:Prims.unit = + Std.Io.Stdio.v__print (Core.Fmt.impl_2__new_v1 (sz 2) + (sz 1) + (let list = [""; "\n"] in + FStar.Pervasives.assert_norm (Prims.eq2 (List.Tot.length list) 2); + Rust_primitives.Hax.array_of_list 2 list) + (let list = + [ + Core.Fmt.Rt.impl_1__new_display #Alloc.String.t_String + (f_stringify #(dyn 1 (fun z -> t_Printable z Alloc.String.t_String)) + #Alloc.String.t_String + #FStar.Tactics.Typeclasses.solve + a + <: + Alloc.String.t_String) + <: + Core.Fmt.Rt.t_Argument + ] + in + FStar.Pervasives.assert_norm (Prims.eq2 (List.Tot.length list) 1); + Rust_primitives.Hax.array_of_list 1 list) + <: + Core.Fmt.t_Arguments) + in + let _:Prims.unit = () in + () +''' diff --git a/test-harness/src/snapshots/toolchain__enum-repr into-coq.snap b/test-harness/src/snapshots/toolchain__enum-repr into-coq.snap index 0a0fb4381..22894e237 100644 --- a/test-harness/src/snapshots/toolchain__enum-repr into-coq.snap +++ b/test-harness/src/snapshots/toolchain__enum-repr into-coq.snap @@ -21,9 +21,7 @@ info: backend_options: ~ --- exit = 0 -stderr = ''' -Compiling enum-repr v0.1.0 (WORKSPACE_ROOT/enum-repr) - Finished dev [unoptimized + debuginfo] target(s) in XXs''' +stderr = 'Finished `dev` profile [unoptimized + debuginfo] target(s) in XXs' [stdout] diagnostics = [] diff --git a/test-harness/src/snapshots/toolchain__enum-repr into-fstar.snap b/test-harness/src/snapshots/toolchain__enum-repr into-fstar.snap index a12f5701a..600085987 100644 --- a/test-harness/src/snapshots/toolchain__enum-repr into-fstar.snap +++ b/test-harness/src/snapshots/toolchain__enum-repr into-fstar.snap @@ -21,9 +21,7 @@ info: backend_options: ~ --- exit = 0 -stderr = ''' -Compiling enum-repr v0.1.0 (WORKSPACE_ROOT/enum-repr) - Finished dev [unoptimized + debuginfo] target(s) in XXs''' +stderr = 'Finished `dev` profile [unoptimized + debuginfo] target(s) in XXs' [stdout] diagnostics = [] diff --git a/test-harness/src/snapshots/toolchain__enum-repr into-ssprove.snap b/test-harness/src/snapshots/toolchain__enum-repr into-ssprove.snap index 17f556d1b..d1e4e4c09 100644 --- a/test-harness/src/snapshots/toolchain__enum-repr into-ssprove.snap +++ b/test-harness/src/snapshots/toolchain__enum-repr into-ssprove.snap @@ -21,9 +21,7 @@ info: backend_options: ~ --- exit = 0 -stderr = ''' -Compiling enum-repr v0.1.0 (WORKSPACE_ROOT/enum-repr) - Finished dev [unoptimized + debuginfo] target(s) in XXs''' +stderr = 'Finished `dev` profile [unoptimized + debuginfo] target(s) in XXs' [stdout] diagnostics = [] diff --git a/test-harness/src/snapshots/toolchain__fnmut lint-rust.snap b/test-harness/src/snapshots/toolchain__fnmut lint-rust.snap deleted file mode 100644 index dfaf541c2..000000000 --- a/test-harness/src/snapshots/toolchain__fnmut lint-rust.snap +++ /dev/null @@ -1,38 +0,0 @@ ---- -source: test-harness/src/harness.rs -expression: snapshot -info: - kind: - Lint: - linter: rust - info: - name: fnmut - manifest: lint/rust/fnmut/Cargo.toml - description: ~ - spec: - optional: false - broken: false - issue_id: ~ - positive: true - snapshot: - stderr: true - stdout: true ---- -exit = 0 -stderr = ''' -Compiling fnmut v0.1.0 (WORKSPACE_ROOT/lint/rust/fnmut) -warning: [Hax] FnMut is not supported - --> lint/rust/fnmut/src/lib.rs:8:12 - | -8 | F: FnMut(u32) -> u8; - | ^^^^^ - -warning: [Hax] FnMut is not supported - --> lint/rust/fnmut/src/lib.rs:16:12 - | -16 | F: FnMut(u32) -> u8, - | ^^^^^ - -warning: `fnmut` (lib) generated 2 warnings - Finished dev [unoptimized + debuginfo] target(s) in XXs''' -stdout = '' diff --git a/test-harness/src/snapshots/toolchain__functions into-coq.snap b/test-harness/src/snapshots/toolchain__functions into-coq.snap new file mode 100644 index 000000000..56ca87c28 --- /dev/null +++ b/test-harness/src/snapshots/toolchain__functions into-coq.snap @@ -0,0 +1,46 @@ +--- +source: test-harness/src/harness.rs +expression: snapshot +info: + kind: + Translate: + backend: coq + info: + name: functions + manifest: functions/Cargo.toml + description: ~ + spec: + optional: false + broken: false + issue_id: ~ + positive: true + snapshot: + stderr: false + stdout: true + include_flag: ~ + backend_options: ~ +--- +exit = 0 + +[stdout] +diagnostics = [] + +[stdout.files] +"Functions.v" = ''' +(* File automatically generated by Hacspec *) +From Hacspec Require Import Hacspec_Lib MachineIntegers. +From Coq Require Import ZArith. +Import List.ListNotations. +Open Scope Z_scope. +Open Scope bool_scope. + +(*Not implemented yet? todo(item)*) + +Definition calling_function_pointer__f (_ : unit) : unit := + tt. + +Definition calling_function_pointer (_ : unit) : unit := + let f_ptr := calling_function_pointer__f : unit -> unit in + let _ := calling_function_pointer__f tt : unit in + tt. +''' diff --git a/test-harness/src/snapshots/toolchain__functions into-fstar.snap b/test-harness/src/snapshots/toolchain__functions into-fstar.snap new file mode 100644 index 000000000..21a6f688a --- /dev/null +++ b/test-harness/src/snapshots/toolchain__functions into-fstar.snap @@ -0,0 +1,42 @@ +--- +source: test-harness/src/harness.rs +expression: snapshot +info: + kind: + Translate: + backend: fstar + info: + name: functions + manifest: functions/Cargo.toml + description: ~ + spec: + optional: false + broken: false + issue_id: ~ + positive: true + snapshot: + stderr: false + stdout: true + include_flag: ~ + backend_options: ~ +--- +exit = 0 + +[stdout] +diagnostics = [] + +[stdout.files] +"Functions.fst" = ''' +module Functions +#set-options "--fuel 0 --ifuel 1 --z3rlimit 15" +open Core +open FStar.Mul + +let calling_function_pointer__f (#v_T: Type0) (_: Prims.unit) : Prims.unit = () + +/// Issue #757 +let calling_function_pointer (_: Prims.unit) : Prims.unit = + let ff_ptr: Prims.unit -> Prims.unit = calling_function_pointer__f in + let _:Prims.unit = calling_function_pointer__f #i32 () in + () +''' diff --git a/test-harness/src/snapshots/toolchain__generics into-fstar.snap b/test-harness/src/snapshots/toolchain__generics into-fstar.snap index db8f3cd46..c875fcfa5 100644 --- a/test-harness/src/snapshots/toolchain__generics into-fstar.snap +++ b/test-harness/src/snapshots/toolchain__generics into-fstar.snap @@ -21,9 +21,7 @@ info: backend_options: ~ --- exit = 0 -stderr = ''' -Compiling generics v0.1.0 (WORKSPACE_ROOT/generics) - Finished dev [unoptimized + debuginfo] target(s) in XXs''' +stderr = 'Finished `dev` profile [unoptimized + debuginfo] target(s) in XXs' [stdout] diagnostics = [] @@ -49,8 +47,8 @@ let impl__Bar__inherent_impl_generics (#v_T: Type0) (v_N: usize) (x: t_Array v_T () class t_Foo (v_Self: Type0) = { - f_const_add_pre:v_N: usize -> v_Self -> bool; - f_const_add_post:v_N: usize -> v_Self -> usize -> bool; + f_const_add_pre:v_N: usize -> v_Self -> Type0; + f_const_add_post:v_N: usize -> v_Self -> usize -> Type0; f_const_add:v_N: usize -> x0: v_Self -> Prims.Pure usize (f_const_add_pre v_N x0) (fun result -> f_const_add_post v_N x0 result) } @@ -67,7 +65,11 @@ let dup (#v_T: Type0) (#[FStar.Tactics.Typeclasses.tcresolve ()] i1: Core.Clone.t_Clone v_T) (x: v_T) - : (v_T & v_T) = Core.Clone.f_clone #v_T x, Core.Clone.f_clone #v_T x <: (v_T & v_T) + : (v_T & v_T) = + Core.Clone.f_clone #v_T #FStar.Tactics.Typeclasses.solve x, + Core.Clone.f_clone #v_T #FStar.Tactics.Typeclasses.solve x + <: + (v_T & v_T) let f (v_N x: usize) : usize = (v_N +! v_N <: usize) +! x @@ -81,8 +83,12 @@ let g : usize = (Core.Option.impl__unwrap_or #usize (Core.Iter.Traits.Iterator.f_max #(Core.Array.Iter.t_IntoIter usize v_N) + #FStar.Tactics.Typeclasses.solve (Core.Iter.Traits.Collect.f_into_iter #(t_Array usize v_N) - (Core.Convert.f_into #v_T #(t_Array usize v_N) arr <: t_Array usize v_N) + #FStar.Tactics.Typeclasses.solve + (Core.Convert.f_into #v_T #(t_Array usize v_N) #FStar.Tactics.Typeclasses.solve arr + <: + t_Array usize v_N) <: Core.Array.Iter.t_IntoIter usize v_N) <: @@ -105,13 +111,12 @@ let call_g (_: Prims.unit) : usize = let foo (v_LEN: usize) (arr: t_Array usize v_LEN) : usize = let acc:usize = v_LEN +! sz 9 in let acc:usize = - Core.Iter.Traits.Iterator.f_fold (Core.Iter.Traits.Collect.f_into_iter #(Core.Ops.Range.t_Range - usize) - ({ Core.Ops.Range.f_start = sz 0; Core.Ops.Range.f_end = v_LEN } - <: - Core.Ops.Range.t_Range usize) - <: - Core.Ops.Range.t_Range usize) + Rust_primitives.Hax.Folds.fold_range (sz 0) + v_LEN + (fun acc temp_1_ -> + let acc:usize = acc in + let _:usize = temp_1_ in + true) acc (fun acc i -> let acc:usize = acc in diff --git a/test-harness/src/snapshots/toolchain__guards into-coq.snap b/test-harness/src/snapshots/toolchain__guards into-coq.snap new file mode 100644 index 000000000..858c6b949 --- /dev/null +++ b/test-harness/src/snapshots/toolchain__guards into-coq.snap @@ -0,0 +1,155 @@ +--- +source: test-harness/src/harness.rs +expression: snapshot +info: + kind: + Translate: + backend: coq + info: + name: guards + manifest: guards/Cargo.toml + description: ~ + spec: + optional: false + broken: false + issue_id: ~ + positive: true + snapshot: + stderr: false + stdout: true + include_flag: ~ + backend_options: ~ +--- +exit = 0 + +[stdout] +diagnostics = [] + +[stdout.files] +"Guards.v" = ''' +(* File automatically generated by Hacspec *) +From Hacspec Require Import Hacspec_Lib MachineIntegers. +From Coq Require Import ZArith. +Import List.ListNotations. +Open Scope Z_scope. +Open Scope bool_scope. + +(*Not implemented yet? todo(item)*) + +Definition equivalent (x : t_Option_t (t_Result_t int32 int32)) : int32 := + match x with + | Option_None => + (@repr WORDSIZE32 0) + | _ => + match match x with + | Option_Some v => + match v with + | Result_Ok y => + Option_Some y + | _ => + Option_Nonet_Option_t int32 + end + | _ => + Option_Nonet_Option_t int32 + end with + | Option_Some y => + y + | Option_None => + match x with + | Option_Some Result_Err y => + y + | _ => + (@repr WORDSIZE32 1) + end + end + end. + +Definition if_guard (x : t_Option_t int32) : int32 := + match match x with + | Option_Some v => + match v>.?(@repr WORDSIZE32 0) with + | true => + Option_Some v + | _ => + Option_Nonet_Option_t int32 + end + | _ => + Option_Nonet_Option_t int32 + end with + | Option_Some x => + x + | Option_None => + (@repr WORDSIZE32 0) + end. + +Definition if_let_guard (x : t_Option_t (t_Result_t int32 int32)) : int32 := + match x with + | Option_None => + (@repr WORDSIZE32 0) + | _ => + match match x with + | Option_Some v => + match v with + | Result_Ok y => + Option_Some y + | _ => + Option_Nonet_Option_t int32 + end + | _ => + Option_Nonet_Option_t int32 + end with + | Option_Some x => + x + | Option_None => + match x with + | Option_Some Result_Err y => + y + | _ => + (@repr WORDSIZE32 1) + end + end + end. + +Definition multiple_guards (x : t_Option_t (t_Result_t int32 int32)) : int32 := + match x with + | Option_None => + (@repr WORDSIZE32 0) + | _ => + match match x with + | Option_Some Result_Ok v => + match Option_Some (v.+(@repr WORDSIZE32 1)) with + | Option_Some (@repr WORDSIZE32 1) => + Option_Some (@repr WORDSIZE32 0) + | _ => + Option_Nonet_Option_t int32 + end + | _ => + Option_Nonet_Option_t int32 + end with + | Option_Some x => + x + | Option_None => + match match x with + | Option_Some v => + match v with + | Result_Ok y => + Option_Some y + | _ => + Option_Nonet_Option_t int32 + end + | _ => + Option_Nonet_Option_t int32 + end with + | Option_Some x => + x + | Option_None => + match x with + | Option_Some Result_Err y => + y + | _ => + (@repr WORDSIZE32 1) + end + end + end + end. +''' diff --git a/test-harness/src/snapshots/toolchain__guards into-fstar.snap b/test-harness/src/snapshots/toolchain__guards into-fstar.snap new file mode 100644 index 000000000..ff12f664a --- /dev/null +++ b/test-harness/src/snapshots/toolchain__guards into-fstar.snap @@ -0,0 +1,110 @@ +--- +source: test-harness/src/harness.rs +expression: snapshot +info: + kind: + Translate: + backend: fstar + info: + name: guards + manifest: guards/Cargo.toml + description: ~ + spec: + optional: false + broken: false + issue_id: ~ + positive: true + snapshot: + stderr: false + stdout: true + include_flag: ~ + backend_options: ~ +--- +exit = 0 + +[stdout] +diagnostics = [] + +[stdout.files] +"Guards.fst" = ''' +module Guards +#set-options "--fuel 0 --ifuel 1 --z3rlimit 15" +open Core +open FStar.Mul + +let equivalent (x: Core.Option.t_Option (Core.Result.t_Result i32 i32)) : i32 = + match x with + | Core.Option.Option_None -> 0l + | _ -> + match + match x with + | Core.Option.Option_Some v -> + (match v with + | Core.Result.Result_Ok y -> Core.Option.Option_Some y <: Core.Option.t_Option i32 + | _ -> Core.Option.Option_None <: Core.Option.t_Option i32) + | _ -> Core.Option.Option_None <: Core.Option.t_Option i32 + with + | Core.Option.Option_Some y -> y + | Core.Option.Option_None -> + match x with + | Core.Option.Option_Some (Core.Result.Result_Err y) -> y + | _ -> 1l + +let if_guard (x: Core.Option.t_Option i32) : i32 = + match + match x with + | Core.Option.Option_Some v -> + (match v >. 0l with + | true -> Core.Option.Option_Some v <: Core.Option.t_Option i32 + | _ -> Core.Option.Option_None <: Core.Option.t_Option i32) + | _ -> Core.Option.Option_None <: Core.Option.t_Option i32 + with + | Core.Option.Option_Some x -> x + | Core.Option.Option_None -> 0l + +let if_let_guard (x: Core.Option.t_Option (Core.Result.t_Result i32 i32)) : i32 = + match x with + | Core.Option.Option_None -> 0l + | _ -> + match + match x with + | Core.Option.Option_Some v -> + (match v with + | Core.Result.Result_Ok y -> Core.Option.Option_Some y <: Core.Option.t_Option i32 + | _ -> Core.Option.Option_None <: Core.Option.t_Option i32) + | _ -> Core.Option.Option_None <: Core.Option.t_Option i32 + with + | Core.Option.Option_Some x -> x + | Core.Option.Option_None -> + match x with + | Core.Option.Option_Some (Core.Result.Result_Err y) -> y + | _ -> 1l + +let multiple_guards (x: Core.Option.t_Option (Core.Result.t_Result i32 i32)) : i32 = + match x with + | Core.Option.Option_None -> 0l + | _ -> + match + match x with + | Core.Option.Option_Some (Core.Result.Result_Ok v) -> + (match Core.Option.Option_Some (v +! 1l) <: Core.Option.t_Option i32 with + | Core.Option.Option_Some 1l -> Core.Option.Option_Some 0l <: Core.Option.t_Option i32 + | _ -> Core.Option.Option_None <: Core.Option.t_Option i32) + | _ -> Core.Option.Option_None <: Core.Option.t_Option i32 + with + | Core.Option.Option_Some x -> x + | Core.Option.Option_None -> + match + match x with + | Core.Option.Option_Some v -> + (match v with + | Core.Result.Result_Ok y -> Core.Option.Option_Some y <: Core.Option.t_Option i32 + | _ -> Core.Option.Option_None <: Core.Option.t_Option i32) + | _ -> Core.Option.Option_None <: Core.Option.t_Option i32 + with + | Core.Option.Option_Some x -> x + | Core.Option.Option_None -> + match x with + | Core.Option.Option_Some (Core.Result.Result_Err y) -> y + | _ -> 1l +''' diff --git a/test-harness/src/snapshots/toolchain__guards into-ssprove.snap b/test-harness/src/snapshots/toolchain__guards into-ssprove.snap new file mode 100644 index 000000000..57b079118 --- /dev/null +++ b/test-harness/src/snapshots/toolchain__guards into-ssprove.snap @@ -0,0 +1,199 @@ +--- +source: test-harness/src/harness.rs +expression: snapshot +info: + kind: + Translate: + backend: ssprove + info: + name: guards + manifest: guards/Cargo.toml + description: ~ + spec: + optional: false + broken: false + issue_id: ~ + positive: true + snapshot: + stderr: false + stdout: true + include_flag: ~ + backend_options: ~ +--- +exit = 0 + +[stdout] +diagnostics = [] + +[stdout.files] +"Guards.v" = ''' +(* File automatically generated by Hacspec *) +Set Warnings "-notation-overridden,-ambiguous-paths". +From Crypt Require Import choice_type Package Prelude. +Import PackageNotation. +From extructures Require Import ord fset. +From mathcomp Require Import word_ssrZ word. +From Jasmin Require Import word. + +From Coq Require Import ZArith. +From Coq Require Import Strings.String. +Import List.ListNotations. +Open Scope list_scope. +Open Scope Z_scope. +Open Scope bool_scope. + +From Hacspec Require Import ChoiceEquality. +From Hacspec Require Import LocationUtility. +From Hacspec Require Import Hacspec_Lib_Comparable. +From Hacspec Require Import Hacspec_Lib_Pre. +From Hacspec Require Import Hacspec_Lib. + +Open Scope hacspec_scope. +Import choice.Choice.Exports. + +Obligation Tactic := (* try timeout 8 *) solve_ssprove_obligations. + +(*Not implemented yet? todo(item)*) + +Equations equivalent {L1 : {fset Location}} {I1 : Interface} (x : both L1 I1 (t_Option (t_Result int32 int32))) : both L1 I1 int32 := + equivalent x := + matchb x with + | Option_None_case => + solve_lift (ret_both (0 : int32)) + | _ => + matchb matchb x with + | Option_Some_case v => + letb v := ret_both ((v) : (t_Result int32 int32)) in + matchb v with + | Result_Ok_case y => + letb y := ret_both ((y) : (int32)) in + Option_Some (solve_lift y) + | _ => + Option_None + end + | _ => + Option_None + end with + | Option_Some_case y => + letb y := ret_both ((y) : (int32)) in + solve_lift y + | Option_None_case => + matchb x with + | Option_Some_case Result_Err y => + letb y := ret_both ((((y))) : (t_Result int32 int32)) in + solve_lift y + | _ => + solve_lift (ret_both (1 : int32)) + end + end + end : both L1 I1 int32. +Fail Next Obligation. + +Equations if_guard {L1 : {fset Location}} {I1 : Interface} (x : both L1 I1 (t_Option int32)) : both L1 I1 int32 := + if_guard x := + matchb matchb x with + | Option_Some_case v => + letb v := ret_both ((v) : (int32)) in + matchb v >.? (ret_both (0 : int32)) with + | true => + Option_Some (solve_lift v) + | _ => + Option_None + end + | _ => + Option_None + end with + | Option_Some_case x => + letb x := ret_both ((x) : (int32)) in + solve_lift x + | Option_None_case => + solve_lift (ret_both (0 : int32)) + end : both L1 I1 int32. +Fail Next Obligation. + +Equations if_let_guard {L1 : {fset Location}} {I1 : Interface} (x : both L1 I1 (t_Option (t_Result int32 int32))) : both L1 I1 int32 := + if_let_guard x := + matchb x with + | Option_None_case => + solve_lift (ret_both (0 : int32)) + | _ => + matchb matchb x with + | Option_Some_case v => + letb v := ret_both ((v) : (t_Result int32 int32)) in + matchb v with + | Result_Ok_case y => + letb y := ret_both ((y) : (int32)) in + Option_Some (solve_lift y) + | _ => + Option_None + end + | _ => + Option_None + end with + | Option_Some_case x => + letb x := ret_both ((x) : (int32)) in + solve_lift x + | Option_None_case => + matchb x with + | Option_Some_case Result_Err y => + letb y := ret_both ((((y))) : (t_Result int32 int32)) in + solve_lift y + | _ => + solve_lift (ret_both (1 : int32)) + end + end + end : both L1 I1 int32. +Fail Next Obligation. + +Equations multiple_guards {L1 : {fset Location}} {I1 : Interface} (x : both L1 I1 (t_Option (t_Result int32 int32))) : both L1 I1 int32 := + multiple_guards x := + matchb x with + | Option_None_case => + solve_lift (ret_both (0 : int32)) + | _ => + matchb matchb x with + | Option_Some_case Result_Ok v => + letb v := ret_both ((((v))) : (t_Result int32 int32)) in + matchb Option_Some (v .+ (ret_both (1 : int32))) with + | Option_Some_case 1 => + letb 1 := ret_both ((1) : (int32)) in + Option_Some (solve_lift (ret_both (0 : int32))) + | _ => + Option_None + end + | _ => + Option_None + end with + | Option_Some_case x => + letb x := ret_both ((x) : (int32)) in + solve_lift x + | Option_None_case => + matchb matchb x with + | Option_Some_case v => + letb v := ret_both ((v) : (t_Result int32 int32)) in + matchb v with + | Result_Ok_case y => + letb y := ret_both ((y) : (int32)) in + Option_Some (solve_lift y) + | _ => + Option_None + end + | _ => + Option_None + end with + | Option_Some_case x => + letb x := ret_both ((x) : (int32)) in + solve_lift x + | Option_None_case => + matchb x with + | Option_Some_case Result_Err y => + letb y := ret_both ((((y))) : (t_Result int32 int32)) in + solve_lift y + | _ => + solve_lift (ret_both (1 : int32)) + end + end + end + end : both L1 I1 int32. +Fail Next Obligation. +''' diff --git a/test-harness/src/snapshots/toolchain__interface-only into-fstar.snap b/test-harness/src/snapshots/toolchain__interface-only into-fstar.snap index b3a95740d..cf2674e03 100644 --- a/test-harness/src/snapshots/toolchain__interface-only into-fstar.snap +++ b/test-harness/src/snapshots/toolchain__interface-only into-fstar.snap @@ -21,9 +21,7 @@ info: backend_options: ~ --- exit = 0 -stderr = ''' -Compiling interface-only v0.1.0 (WORKSPACE_ROOT/cli/interface-only) - Finished dev [unoptimized + debuginfo] target(s) in XXs''' +stderr = 'Finished `dev` profile [unoptimized + debuginfo] target(s) in XXs' [stdout] diagnostics = [] diff --git a/test-harness/src/snapshots/toolchain__let-else into-coq.snap b/test-harness/src/snapshots/toolchain__let-else into-coq.snap new file mode 100644 index 000000000..85110e910 --- /dev/null +++ b/test-harness/src/snapshots/toolchain__let-else into-coq.snap @@ -0,0 +1,55 @@ +--- +source: test-harness/src/harness.rs +expression: snapshot +info: + kind: + Translate: + backend: coq + info: + name: let-else + manifest: let-else/Cargo.toml + description: ~ + spec: + optional: false + broken: false + issue_id: ~ + positive: true + snapshot: + stderr: false + stdout: true + include_flag: ~ + backend_options: ~ +--- +exit = 0 + +[stdout] +diagnostics = [] + +[stdout.files] +"Let_else.v" = ''' +(* File automatically generated by Hacspec *) +From Hacspec Require Import Hacspec_Lib MachineIntegers. +From Coq Require Import ZArith. +Import List.ListNotations. +Open Scope Z_scope. +Open Scope bool_scope. + +(*Not implemented yet? todo(item)*) + +Definition let_else (opt : t_Option_t int32) : bool := + run match opt with + | Option_Some x => + ControlFlow_Continue true + | _ => + ControlFlow_Break false + end. + +Definition let_else_different_type (opt : t_Option_t int32) : bool := + run (let hoist1 := match opt with + | Option_Some x => + ControlFlow_Continue (Option_Some (x.+(@repr WORDSIZE32 1))) + | _ => + ControlFlow_Break false + end : t_Option_t int32 in + ControlFlow_Continue (let_else hoist1)). +''' diff --git a/test-harness/src/snapshots/toolchain__let-else into-fstar.snap b/test-harness/src/snapshots/toolchain__let-else into-fstar.snap new file mode 100644 index 000000000..44ed74878 --- /dev/null +++ b/test-harness/src/snapshots/toolchain__let-else into-fstar.snap @@ -0,0 +1,45 @@ +--- +source: test-harness/src/harness.rs +expression: snapshot +info: + kind: + Translate: + backend: fstar + info: + name: let-else + manifest: let-else/Cargo.toml + description: ~ + spec: + optional: false + broken: false + issue_id: ~ + positive: true + snapshot: + stderr: false + stdout: true + include_flag: ~ + backend_options: ~ +--- +exit = 0 + +[stdout] +diagnostics = [] + +[stdout.files] +"Let_else.fst" = ''' +module Let_else +#set-options "--fuel 0 --ifuel 1 --z3rlimit 15" +open Core +open FStar.Mul + +let let_else (opt: Core.Option.t_Option u32) : bool = + match opt with + | Core.Option.Option_Some x -> true + | _ -> false + +let let_else_different_type (opt: Core.Option.t_Option u32) : bool = + match opt with + | Core.Option.Option_Some x -> + let_else (Core.Option.Option_Some (x +! 1ul <: u32) <: Core.Option.t_Option u32) + | _ -> false +''' diff --git a/test-harness/src/snapshots/toolchain__let-else into-ssprove.snap b/test-harness/src/snapshots/toolchain__let-else into-ssprove.snap new file mode 100644 index 000000000..3fe94349f --- /dev/null +++ b/test-harness/src/snapshots/toolchain__let-else into-ssprove.snap @@ -0,0 +1,80 @@ +--- +source: test-harness/src/harness.rs +expression: snapshot +info: + kind: + Translate: + backend: ssprove + info: + name: let-else + manifest: let-else/Cargo.toml + description: ~ + spec: + optional: false + broken: false + issue_id: ~ + positive: true + snapshot: + stderr: false + stdout: true + include_flag: ~ + backend_options: ~ +--- +exit = 0 + +[stdout] +diagnostics = [] + +[stdout.files] +"Let_else.v" = ''' +(* File automatically generated by Hacspec *) +Set Warnings "-notation-overridden,-ambiguous-paths". +From Crypt Require Import choice_type Package Prelude. +Import PackageNotation. +From extructures Require Import ord fset. +From mathcomp Require Import word_ssrZ word. +From Jasmin Require Import word. + +From Coq Require Import ZArith. +From Coq Require Import Strings.String. +Import List.ListNotations. +Open Scope list_scope. +Open Scope Z_scope. +Open Scope bool_scope. + +From Hacspec Require Import ChoiceEquality. +From Hacspec Require Import LocationUtility. +From Hacspec Require Import Hacspec_Lib_Comparable. +From Hacspec Require Import Hacspec_Lib_Pre. +From Hacspec Require Import Hacspec_Lib. + +Open Scope hacspec_scope. +Import choice.Choice.Exports. + +Obligation Tactic := (* try timeout 8 *) solve_ssprove_obligations. + +(*Not implemented yet? todo(item)*) + +Equations let_else {L1 : {fset Location}} {I1 : Interface} (opt : both L1 I1 (t_Option int32)) : both L1 I1 'bool := + let_else opt := + solve_lift (run (matchb opt with + | Option_Some_case x => + letb x := ret_both ((x) : (int32)) in + ControlFlow_Continue (solve_lift (ret_both (true : 'bool))) + | _ => + ControlFlow_Break (solve_lift (ret_both (false : 'bool))) + end)) : both L1 I1 'bool. +Fail Next Obligation. + +Equations let_else_different_type {L1 : {fset Location}} {I1 : Interface} (opt : both L1 I1 (t_Option int32)) : both L1 I1 'bool := + let_else_different_type opt := + solve_lift (run (letm[choice_typeMonad.result_bind_code 'bool] hoist1 := matchb opt with + | Option_Some_case x => + letb x := ret_both ((x) : (int32)) in + ControlFlow_Continue (Option_Some (solve_lift (x .+ (ret_both (1 : int32))))) + | _ => + ControlFlow_Break (solve_lift (ret_both (false : 'bool))) + end in + ControlFlow_Continue (let_else hoist1))) : both L1 I1 'bool. +Fail Next Obligation. +''' diff --git a/test-harness/src/snapshots/toolchain__literals into-coq.snap b/test-harness/src/snapshots/toolchain__literals into-coq.snap index fa56c7eca..c18c543fa 100644 --- a/test-harness/src/snapshots/toolchain__literals into-coq.snap +++ b/test-harness/src/snapshots/toolchain__literals into-coq.snap @@ -21,9 +21,7 @@ info: backend_options: ~ --- exit = 0 -stderr = ''' -Compiling literals v0.1.0 (WORKSPACE_ROOT/literals) - Finished dev [unoptimized + debuginfo] target(s) in XXs''' +stderr = 'Finished `dev` profile [unoptimized + debuginfo] target(s) in XXs' [stdout] diagnostics = [] @@ -90,13 +88,13 @@ Definition numeric (_ : unit) : unit := let (_ : int128) := (@repr WORDSIZE128 22222222222222222222) : int128 in tt. +Definition panic_with_msg (_ : unit) : unit := + never_to_any (panic_fmt (impl_2__new_const (array_from_list [with msg]))). + Definition empty_array (_ : unit) : unit := let (_ : seq int8) := unsize !TODO empty array! : seq int8 in tt. -Definition panic_with_msg (_ : unit) : unit := - never_to_any (panic_fmt (impl_2__new_const (unsize (array_from_list [with msg])))). - Record t_Foo : Type := { f_field : int8; }. diff --git a/test-harness/src/snapshots/toolchain__literals into-fstar.snap b/test-harness/src/snapshots/toolchain__literals into-fstar.snap index f7bfd661b..be54f22ba 100644 --- a/test-harness/src/snapshots/toolchain__literals into-fstar.snap +++ b/test-harness/src/snapshots/toolchain__literals into-fstar.snap @@ -21,9 +21,7 @@ info: backend_options: ~ --- exit = 0 -stderr = ''' -Compiling literals v0.1.0 (WORKSPACE_ROOT/literals) - Finished dev [unoptimized + debuginfo] target(s) in XXs''' +stderr = 'Finished `dev` profile [unoptimized + debuginfo] target(s) in XXs' [stdout] diagnostics = [] @@ -147,26 +145,26 @@ let numeric (_: Prims.unit) : Prims.unit = let (_: u128):u128 = pub_u128 22222222222222222222 in () -let empty_array (_: Prims.unit) : Prims.unit = - let (_: t_Slice u8):t_Slice u8 = - Rust_primitives.unsize (let list:Prims.list u8 = [] in - FStar.Pervasives.assert_norm (Prims.eq2 (List.Tot.length list) 0); - Rust_primitives.Hax.array_of_list 0 list) - in - () - let panic_with_msg (_: Prims.unit) : Prims.unit = - Rust_primitives.Hax.never_to_any (Core.Panicking.panic_fmt (Core.Fmt.impl_2__new_const (Rust_primitives.unsize - (let list = ["with msg"] in - FStar.Pervasives.assert_norm (Prims.eq2 (List.Tot.length list) 1); - Rust_primitives.Hax.array_of_list 1 list) - <: - t_Slice string) + Rust_primitives.Hax.never_to_any (Core.Panicking.panic_fmt (Core.Fmt.impl_2__new_const (sz 1) + (let list = ["with msg"] in + FStar.Pervasives.assert_norm (Prims.eq2 (List.Tot.length list) 1); + Rust_primitives.Hax.array_of_list 1 list) <: Core.Fmt.t_Arguments) <: Rust_primitives.Hax.t_Never) +let empty_array (_: Prims.unit) : Prims.unit = + let (_: t_Slice u8):t_Slice u8 = + (let list:Prims.list u8 = [] in + FStar.Pervasives.assert_norm (Prims.eq2 (List.Tot.length list) 0); + Rust_primitives.Hax.array_of_list 0 list) + <: + t_Slice u8 + in + () + type t_Foo = { f_field:u8 } let v_CONSTANT: t_Foo = { f_field = 3uy } <: t_Foo diff --git a/test-harness/src/snapshots/toolchain__loops into-fstar.snap b/test-harness/src/snapshots/toolchain__loops into-fstar.snap index 169518fc5..695f8bf5b 100644 --- a/test-harness/src/snapshots/toolchain__loops into-fstar.snap +++ b/test-harness/src/snapshots/toolchain__loops into-fstar.snap @@ -21,9 +21,7 @@ info: backend_options: ~ --- exit = 0 -stderr = ''' -Compiling loops v0.1.0 (WORKSPACE_ROOT/loops) - Finished dev [unoptimized + debuginfo] target(s) in XXs''' +stderr = 'Finished `dev` profile [unoptimized + debuginfo] target(s) in XXs' [stdout] diagnostics = [] @@ -41,13 +39,20 @@ let chunks (v_CHUNK_LEN: usize) (arr: Alloc.Vec.t_Vec usize Alloc.Alloc.t_Global let acc:usize = sz 0 in let chunks:Core.Slice.Iter.t_ChunksExact usize = Core.Slice.impl__chunks_exact #usize - (Core.Ops.Deref.f_deref #(Alloc.Vec.t_Vec usize Alloc.Alloc.t_Global) arr <: t_Slice usize) + (Core.Ops.Deref.f_deref #(Alloc.Vec.t_Vec usize Alloc.Alloc.t_Global) + #FStar.Tactics.Typeclasses.solve + arr + <: + t_Slice usize) v_CHUNK_LEN in let acc:usize = Core.Iter.Traits.Iterator.f_fold (Core.Iter.Traits.Collect.f_into_iter #(Core.Slice.Iter.t_ChunksExact usize) - (Core.Clone.f_clone #(Core.Slice.Iter.t_ChunksExact usize) chunks + #FStar.Tactics.Typeclasses.solve + (Core.Clone.f_clone #(Core.Slice.Iter.t_ChunksExact usize) + #FStar.Tactics.Typeclasses.solve + chunks <: Core.Slice.Iter.t_ChunksExact usize) <: @@ -59,6 +64,7 @@ let chunks (v_CHUNK_LEN: usize) (arr: Alloc.Vec.t_Vec usize Alloc.Alloc.t_Global let mean:usize = sz 0 in let mean:usize = Core.Iter.Traits.Iterator.f_fold (Core.Iter.Traits.Collect.f_into_iter #(t_Slice usize) + #FStar.Tactics.Typeclasses.solve chunk <: Core.Slice.Iter.t_Iter usize) @@ -73,7 +79,8 @@ let chunks (v_CHUNK_LEN: usize) (arr: Alloc.Vec.t_Vec usize Alloc.Alloc.t_Global in let acc:usize = Core.Iter.Traits.Iterator.f_fold (Core.Iter.Traits.Collect.f_into_iter #(t_Slice usize) - (Core.Slice.Iter.impl_87__remainder #usize chunks <: t_Slice usize) + #FStar.Tactics.Typeclasses.solve + (Core.Slice.Iter.impl_88__remainder #usize chunks <: t_Slice usize) <: Core.Slice.Iter.t_Iter usize) acc @@ -89,7 +96,9 @@ let composed_range (n: usize) : usize = let acc:usize = Core.Iter.Traits.Iterator.f_fold (Core.Iter.Traits.Collect.f_into_iter #(Core.Iter.Adapters.Chain.t_Chain (Core.Ops.Range.t_Range usize) (Core.Ops.Range.t_Range usize)) + #FStar.Tactics.Typeclasses.solve (Core.Iter.Traits.Iterator.f_chain #(Core.Ops.Range.t_Range usize) + #FStar.Tactics.Typeclasses.solve #(Core.Ops.Range.t_Range usize) ({ Core.Ops.Range.f_start = sz 0; Core.Ops.Range.f_end = n } <: @@ -119,9 +128,13 @@ let enumerate_chunks (arr: Alloc.Vec.t_Vec usize Alloc.Alloc.t_Global) : usize = let acc:usize = Core.Iter.Traits.Iterator.f_fold (Core.Iter.Traits.Collect.f_into_iter #(Core.Iter.Adapters.Enumerate.t_Enumerate (Core.Slice.Iter.t_Chunks usize)) + #FStar.Tactics.Typeclasses.solve (Core.Iter.Traits.Iterator.f_enumerate #(Core.Slice.Iter.t_Chunks usize) + #FStar.Tactics.Typeclasses.solve (Core.Slice.impl__chunks #usize - (Core.Ops.Deref.f_deref #(Alloc.Vec.t_Vec usize Alloc.Alloc.t_Global) arr + (Core.Ops.Deref.f_deref #(Alloc.Vec.t_Vec usize Alloc.Alloc.t_Global) + #FStar.Tactics.Typeclasses.solve + arr <: t_Slice usize) (sz 4) @@ -135,14 +148,11 @@ let enumerate_chunks (arr: Alloc.Vec.t_Vec usize Alloc.Alloc.t_Global) : usize = (fun acc temp_1_ -> let acc:usize = acc in let i, chunk:(usize & t_Slice usize) = temp_1_ in - Core.Iter.Traits.Iterator.f_fold (Core.Iter.Traits.Collect.f_into_iter #(Core.Iter.Adapters.Enumerate.t_Enumerate - (Core.Slice.Iter.t_Iter usize)) - (Core.Iter.Traits.Iterator.f_enumerate #(Core.Slice.Iter.t_Iter usize) - (Core.Slice.impl__iter #usize chunk <: Core.Slice.Iter.t_Iter usize) - <: - Core.Iter.Adapters.Enumerate.t_Enumerate (Core.Slice.Iter.t_Iter usize)) - <: - Core.Iter.Adapters.Enumerate.t_Enumerate (Core.Slice.Iter.t_Iter usize)) + Rust_primitives.Hax.Folds.fold_enumerated_slice chunk + (fun acc temp_1_ -> + let acc:usize = acc in + let _:usize = temp_1_ in + true) acc (fun acc temp_1_ -> let acc:usize = acc in @@ -155,11 +165,12 @@ let enumerate_chunks (arr: Alloc.Vec.t_Vec usize Alloc.Alloc.t_Global) : usize = let f (_: Prims.unit) : u8 = let acc:u8 = 0uy in - Core.Iter.Traits.Iterator.f_fold (Core.Iter.Traits.Collect.f_into_iter #(Core.Ops.Range.t_Range u8 - ) - ({ Core.Ops.Range.f_start = 1uy; Core.Ops.Range.f_end = 10uy } <: Core.Ops.Range.t_Range u8) - <: - Core.Ops.Range.t_Range u8) + Rust_primitives.Hax.Folds.fold_range 1uy + 10uy + (fun acc temp_1_ -> + let acc:u8 = acc in + let _:u8 = temp_1_ in + true) acc (fun acc i -> let acc:u8 = acc in @@ -173,8 +184,11 @@ let iterator (arr: Alloc.Vec.t_Vec usize Alloc.Alloc.t_Global) : usize = let acc:usize = Core.Iter.Traits.Iterator.f_fold (Core.Iter.Traits.Collect.f_into_iter #(Core.Slice.Iter.t_Iter usize) + #FStar.Tactics.Typeclasses.solve (Core.Slice.impl__iter #usize - (Core.Ops.Deref.f_deref #(Alloc.Vec.t_Vec usize Alloc.Alloc.t_Global) arr + (Core.Ops.Deref.f_deref #(Alloc.Vec.t_Vec usize Alloc.Alloc.t_Global) + #FStar.Tactics.Typeclasses.solve + arr <: t_Slice usize) <: @@ -194,8 +208,11 @@ let nested (arr: Alloc.Vec.t_Vec usize Alloc.Alloc.t_Global) : usize = let acc:usize = Core.Iter.Traits.Iterator.f_fold (Core.Iter.Traits.Collect.f_into_iter #(Core.Slice.Iter.t_Iter usize) + #FStar.Tactics.Typeclasses.solve (Core.Slice.impl__iter #usize - (Core.Ops.Deref.f_deref #(Alloc.Vec.t_Vec usize Alloc.Alloc.t_Global) arr + (Core.Ops.Deref.f_deref #(Alloc.Vec.t_Vec usize Alloc.Alloc.t_Global) + #FStar.Tactics.Typeclasses.solve + arr <: t_Slice usize) <: @@ -208,7 +225,9 @@ let nested (arr: Alloc.Vec.t_Vec usize Alloc.Alloc.t_Global) : usize = let item:usize = item in Core.Iter.Traits.Iterator.f_fold (Core.Iter.Traits.Collect.f_into_iter #(Core.Iter.Adapters.Rev.t_Rev (Core.Ops.Range.t_Range usize)) + #FStar.Tactics.Typeclasses.solve (Core.Iter.Traits.Iterator.f_rev #(Core.Ops.Range.t_Range usize) + #FStar.Tactics.Typeclasses.solve ({ Core.Ops.Range.f_start = sz 0; Core.Ops.Range.f_end = item } <: Core.Ops.Range.t_Range usize) @@ -223,10 +242,13 @@ let nested (arr: Alloc.Vec.t_Vec usize Alloc.Alloc.t_Global) : usize = let acc:usize = acc +! sz 1 in Core.Iter.Traits.Iterator.f_fold (Core.Iter.Traits.Collect.f_into_iter #(Core.Iter.Adapters.Zip.t_Zip (Core.Slice.Iter.t_Iter usize) (Core.Ops.Range.t_Range usize)) + #FStar.Tactics.Typeclasses.solve (Core.Iter.Traits.Iterator.f_zip #(Core.Slice.Iter.t_Iter usize) + #FStar.Tactics.Typeclasses.solve #(Core.Ops.Range.t_Range usize) (Core.Slice.impl__iter #usize (Core.Ops.Deref.f_deref #(Alloc.Vec.t_Vec usize Alloc.Alloc.t_Global) + #FStar.Tactics.Typeclasses.solve arr <: t_Slice usize) @@ -256,6 +278,7 @@ let pattern (arr: Alloc.Vec.t_Vec (usize & usize) Alloc.Alloc.t_Global) : usize let acc:usize = Core.Iter.Traits.Iterator.f_fold (Core.Iter.Traits.Collect.f_into_iter #(Alloc.Vec.t_Vec (usize & usize) Alloc.Alloc.t_Global) + #FStar.Tactics.Typeclasses.solve arr <: Alloc.Vec.Into_iter.t_IntoIter (usize & usize) Alloc.Alloc.t_Global) @@ -270,13 +293,12 @@ let pattern (arr: Alloc.Vec.t_Vec (usize & usize) Alloc.Alloc.t_Global) : usize let range1 (_: Prims.unit) : usize = let acc:usize = sz 0 in let acc:usize = - Core.Iter.Traits.Iterator.f_fold (Core.Iter.Traits.Collect.f_into_iter #(Core.Ops.Range.t_Range - usize) - ({ Core.Ops.Range.f_start = sz 0; Core.Ops.Range.f_end = sz 15 } - <: - Core.Ops.Range.t_Range usize) - <: - Core.Ops.Range.t_Range usize) + Rust_primitives.Hax.Folds.fold_range (sz 0) + (sz 15) + (fun acc temp_1_ -> + let acc:usize = acc in + let _:usize = temp_1_ in + true) acc (fun acc i -> let acc:usize = acc in @@ -288,13 +310,12 @@ let range1 (_: Prims.unit) : usize = let range2 (n: usize) : usize = let acc:usize = sz 0 in let acc:usize = - Core.Iter.Traits.Iterator.f_fold (Core.Iter.Traits.Collect.f_into_iter #(Core.Ops.Range.t_Range - usize) - ({ Core.Ops.Range.f_start = sz 0; Core.Ops.Range.f_end = n +! sz 10 <: usize } - <: - Core.Ops.Range.t_Range usize) - <: - Core.Ops.Range.t_Range usize) + Rust_primitives.Hax.Folds.fold_range (sz 0) + (n +! sz 10 <: usize) + (fun acc temp_1_ -> + let acc:usize = acc in + let _:usize = temp_1_ in + true) acc (fun acc i -> let acc:usize = acc in @@ -308,7 +329,9 @@ let rev_range (n: usize) : usize = let acc:usize = Core.Iter.Traits.Iterator.f_fold (Core.Iter.Traits.Collect.f_into_iter #(Core.Iter.Adapters.Rev.t_Rev (Core.Ops.Range.t_Range usize)) + #FStar.Tactics.Typeclasses.solve (Core.Iter.Traits.Iterator.f_rev #(Core.Ops.Range.t_Range usize) + #FStar.Tactics.Typeclasses.solve ({ Core.Ops.Range.f_start = sz 0; Core.Ops.Range.f_end = n } <: Core.Ops.Range.t_Range usize) @@ -324,6 +347,72 @@ let rev_range (n: usize) : usize = in acc ''' +"Loops.Recognized_loops.fst" = ''' +module Loops.Recognized_loops +#set-options "--fuel 0 --ifuel 1 --z3rlimit 15" +open Core +open FStar.Mul + +let enumerated_chunked_slice (#v_T: Type0) (slice: t_Slice v_T) : u64 = + let count:u64 = 0uL in + Rust_primitives.Hax.Folds.fold_enumerated_chunked_slice (sz 3) + slice + (fun count i -> + let count:u64 = count in + let i:usize = i in + i <= Core.Slice.impl__len #v_T slice) + count + (fun count i -> + let count:u64 = count in + let i:(usize & t_Slice v_T) = i in + let count:u64 = count +! 3uL in + count) + +let enumerated_slice (#v_T: Type0) (slice: t_Slice v_T) : u64 = + let count:u64 = 0uL in + Rust_primitives.Hax.Folds.fold_enumerated_slice slice + (fun count i -> + let count:u64 = count in + let i:usize = i in + i <=. sz 10 <: bool) + count + (fun count i -> + let count:u64 = count in + let i:(usize & v_T) = i in + let count:u64 = count +! 2uL in + count) + +let range (_: Prims.unit) : u64 = + let count:u64 = 0uL in + Rust_primitives.Hax.Folds.fold_range 0uy + 10uy + (fun count i -> + let count:u64 = count in + let i:u8 = i in + i <=. 10uy <: bool) + count + (fun count i -> + let count:u64 = count in + let i:u8 = i in + let count:u64 = count +! 1uL in + count) + +let range_step_by (_: Prims.unit) : u64 = + let count:u64 = 0uL in + Rust_primitives.Hax.Folds.fold_range_step_by 0uy + 10uy + (sz 2) + (fun count i -> + let count:u64 = count in + let i:u8 = i in + i <=. 10uy <: bool) + count + (fun count i -> + let count:u64 = count in + let i:u8 = i in + let count:u64 = count +! 1uL in + count) +''' "Loops.While_loops.fst" = ''' module Loops.While_loops #set-options "--fuel 0 --ifuel 1 --z3rlimit 15" diff --git a/test-harness/src/snapshots/toolchain__mut-ref-functionalization into-fstar.snap b/test-harness/src/snapshots/toolchain__mut-ref-functionalization into-fstar.snap index 76f5002cd..955a69474 100644 --- a/test-harness/src/snapshots/toolchain__mut-ref-functionalization into-fstar.snap +++ b/test-harness/src/snapshots/toolchain__mut-ref-functionalization into-fstar.snap @@ -33,8 +33,8 @@ open Core open FStar.Mul class t_FooTrait (v_Self: Type0) = { - f_z_pre:v_Self -> bool; - f_z_post:v_Self -> v_Self -> bool; + f_z_pre:v_Self -> Type0; + f_z_post:v_Self -> v_Self -> Type0; f_z:x0: v_Self -> Prims.Pure v_Self (f_z_pre x0) (fun result -> f_z_post x0 result) } @@ -127,9 +127,9 @@ let index_mutation_unsize (x: t_Array u8 (sz 12)) : u8 = Core.Ops.Range.t_Range usize ] <: t_Slice u8) - (Rust_primitives.unsize (let list = [1uy; 2uy] in - FStar.Pervasives.assert_norm (Prims.eq2 (List.Tot.length list) 2); - Rust_primitives.Hax.array_of_list 2 list) + ((let list = [1uy; 2uy] in + FStar.Pervasives.assert_norm (Prims.eq2 (List.Tot.length list) 2); + Rust_primitives.Hax.array_of_list 2 list) <: t_Slice u8) <: @@ -195,13 +195,12 @@ let impl__S__update (self: t_S) (x: u8) : t_S = let foo (lhs rhs: t_S) : t_S = let lhs:t_S = - Core.Iter.Traits.Iterator.f_fold (Core.Iter.Traits.Collect.f_into_iter #(Core.Ops.Range.t_Range - usize) - ({ Core.Ops.Range.f_start = sz 0; Core.Ops.Range.f_end = sz 1 } - <: - Core.Ops.Range.t_Range usize) - <: - Core.Ops.Range.t_Range usize) + Rust_primitives.Hax.Folds.fold_range (sz 0) + (sz 1) + (fun lhs temp_1_ -> + let lhs:t_S = lhs in + let _:usize = temp_1_ in + true) lhs (fun lhs i -> let lhs:t_S = lhs in @@ -243,13 +242,12 @@ let g (x: t_Pair (Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global)) : Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global = let x:t_Pair (Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global) = x in let x:t_Pair (Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global) = - Core.Iter.Traits.Iterator.f_fold (Core.Iter.Traits.Collect.f_into_iter #(Core.Ops.Range.t_Range - u8) - ({ Core.Ops.Range.f_start = 1uy; Core.Ops.Range.f_end = 10uy } - <: - Core.Ops.Range.t_Range u8) - <: - Core.Ops.Range.t_Range u8) + Rust_primitives.Hax.Folds.fold_range 1uy + 10uy + (fun x temp_1_ -> + let x:t_Pair (Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global) = x in + let _:u8 = temp_1_ in + true) x (fun x i -> let x:t_Pair (Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global) = x in diff --git a/test-harness/src/snapshots/toolchain__mut_arg lint-hacspec.snap b/test-harness/src/snapshots/toolchain__mut_arg lint-hacspec.snap deleted file mode 100644 index 82d85c40c..000000000 --- a/test-harness/src/snapshots/toolchain__mut_arg lint-hacspec.snap +++ /dev/null @@ -1,32 +0,0 @@ ---- -source: test-harness/src/harness.rs -expression: snapshot -info: - kind: - Lint: - linter: hacspec - info: - name: mut_arg - manifest: lint/hacspec/mut_args/Cargo.toml - description: ~ - spec: - optional: false - broken: false - issue_id: ~ - positive: true - snapshot: - stderr: true - stdout: true ---- -exit = 0 -stderr = ''' -Compiling mut_arg v0.1.0 (WORKSPACE_ROOT/lint/hacspec/mut_args) -warning: [Hax] Mutable arguments are not supported - --> lint/hacspec/mut_args/src/lib.rs:1:23 - | -1 | pub fn add(left: &mut usize, right: usize) { - | ^^^^^ - -warning: `mut_arg` (lib) generated 1 warning - Finished dev [unoptimized + debuginfo] target(s) in XXs''' -stdout = '' diff --git a/test-harness/src/snapshots/toolchain__naming into-coq.snap b/test-harness/src/snapshots/toolchain__naming into-coq.snap index 49243dce6..300f02c43 100644 --- a/test-harness/src/snapshots/toolchain__naming into-coq.snap +++ b/test-harness/src/snapshots/toolchain__naming into-coq.snap @@ -20,10 +20,12 @@ info: include_flag: ~ backend_options: ~ --- -exit = 0 - -[stdout] -diagnostics = [] +exit = 1 +[[stdout.diagnostics]] +message = ''' +(Coq backend) something is not implemented yet. +[ty] node str''' +spans = ['Span { lo: Loc { line: 160, col: 0 }, hi: Loc { line: 160, col: 43 }, filename: Real(LocalPath("naming/src/lib.rs")), rust_span_data: None }'] [stdout.files] "Naming.v" = ''' @@ -92,6 +94,8 @@ Definition ff__g__impl_1__g (self : t_Foo_t) : uint_size := Definition reserved_names (val : int8) (noeq : int8) (of : int8) : int8 := (val.+noeq).+of. +(*item error backend*) + Record t_Arity1 (T : _) : Type := { 0 : T; }. @@ -163,11 +167,11 @@ Open Scope bool_scope. (*Not implemented yet? todo(item)*) Definition debug (label : int32) (value : int32) : unit := - let _ := v__print (impl_2__new_v1 (unsize (array_from_list [[; + let _ := v__print (impl_2__new_v1 (array_from_list [[; ] a=; -])) (unsize (array_from_list [impl_1__new_display label; - impl_1__new_display value]))) : unit in +]) (array_from_list [impl_1__new_display label; + impl_1__new_display value])) : unit in tt. Definition f (_ : unit) : unit := diff --git a/test-harness/src/snapshots/toolchain__naming into-fstar.snap b/test-harness/src/snapshots/toolchain__naming into-fstar.snap index 68c009f19..585900c82 100644 --- a/test-harness/src/snapshots/toolchain__naming into-fstar.snap +++ b/test-harness/src/snapshots/toolchain__naming into-fstar.snap @@ -34,23 +34,19 @@ open FStar.Mul let debug (label value: u32) : Prims.unit = let _:Prims.unit = - Std.Io.Stdio.v__print (Core.Fmt.impl_2__new_v1 (Rust_primitives.unsize (let list = - ["["; "] a="; "\n"] - in - FStar.Pervasives.assert_norm (Prims.eq2 (List.Tot.length list) 3); - Rust_primitives.Hax.array_of_list 3 list) - <: - t_Slice string) - (Rust_primitives.unsize (let list = - [ - Core.Fmt.Rt.impl_1__new_display #u32 label <: Core.Fmt.Rt.t_Argument; - Core.Fmt.Rt.impl_1__new_display #u32 value <: Core.Fmt.Rt.t_Argument - ] - in - FStar.Pervasives.assert_norm (Prims.eq2 (List.Tot.length list) 2); - Rust_primitives.Hax.array_of_list 2 list) - <: - t_Slice Core.Fmt.Rt.t_Argument) + Std.Io.Stdio.v__print (Core.Fmt.impl_2__new_v1 (sz 3) + (sz 2) + (let list = ["["; "] a="; "\n"] in + FStar.Pervasives.assert_norm (Prims.eq2 (List.Tot.length list) 3); + Rust_primitives.Hax.array_of_list 3 list) + (let list = + [ + Core.Fmt.Rt.impl_1__new_display #u32 label <: Core.Fmt.Rt.t_Argument; + Core.Fmt.Rt.impl_1__new_display #u32 value <: Core.Fmt.Rt.t_Argument + ] + in + FStar.Pervasives.assert_norm (Prims.eq2 (List.Tot.length list) 2); + Rust_primitives.Hax.array_of_list 2 list) <: Core.Fmt.t_Arguments) in @@ -143,6 +139,9 @@ let ff__g__impl_1__g (self: t_Foo) : usize = sz 1 let reserved_names (v_val v_noeq v_of: u8) : u8 = (v_val +! v_noeq <: u8) +! v_of +/// From issue https://github.com/hacspec/hax/issues/839 +let string_shadows (v_string n: string) : Prims.unit = () + type t_Arity1 (v_T: Type0) = | Arity1 : v_T -> t_Arity1 v_T [@@ FStar.Tactics.Typeclasses.tcinstance] diff --git a/test-harness/src/snapshots/toolchain__pattern-or into-coq.snap b/test-harness/src/snapshots/toolchain__pattern-or into-coq.snap index 982cd7001..a7897333d 100644 --- a/test-harness/src/snapshots/toolchain__pattern-or into-coq.snap +++ b/test-harness/src/snapshots/toolchain__pattern-or into-coq.snap @@ -21,9 +21,7 @@ info: backend_options: ~ --- exit = 0 -stderr = ''' -Compiling pattern-or v0.1.0 (WORKSPACE_ROOT/pattern-or) - Finished dev [unoptimized + debuginfo] target(s) in XXs''' +stderr = 'Finished `dev` profile [unoptimized + debuginfo] target(s) in XXs' [stdout] diagnostics = [] @@ -56,4 +54,38 @@ Definition bar (x : t_E_t) : unit := | E_A | E_B => tt end. + +Definition deep (x : int32 × t_Option_t int32) : int32 := + match x with + | '((@repr WORDSIZE32 1) | (@repr WORDSIZE32 2),Option_Some (@repr WORDSIZE32 3) | (@repr WORDSIZE32 4)) => + (@repr WORDSIZE32 0) + | '(x,_) => + x + end. + +Definition deep_capture (x : t_Result_t (int32 × int32) (int32 × int32)) : int32 := + match x with + | Result_Ok ((@repr WORDSIZE32 1) | (@repr WORDSIZE32 2),x) | Result_Err ((@repr WORDSIZE32 3) | (@repr WORDSIZE32 4),x) => + x + | Result_Ok (x,_) | Result_Err (x,_) => + x + end. + +Definition equivalent (x : int32 × t_Option_t int32) : int32 := + match x with + | '((@repr WORDSIZE32 1),Option_Some (@repr WORDSIZE32 3)) | '((@repr WORDSIZE32 1),Option_Some (@repr WORDSIZE32 4)) | '((@repr WORDSIZE32 2),Option_Some (@repr WORDSIZE32 3)) | '((@repr WORDSIZE32 2),Option_Some (@repr WORDSIZE32 4)) => + (@repr WORDSIZE32 0) + | '(x,_) => + x + end. + +Definition nested (x : t_Option_t int32) : int32 := + match x with + | Option_Some (@repr WORDSIZE32 1) | (@repr WORDSIZE32 2) => + (@repr WORDSIZE32 1) + | Option_Some x => + x + | Option_None => + (@repr WORDSIZE32 0) + end. ''' diff --git a/test-harness/src/snapshots/toolchain__pattern-or into-fstar.snap b/test-harness/src/snapshots/toolchain__pattern-or into-fstar.snap index 7f00c86cf..9fdc477aa 100644 --- a/test-harness/src/snapshots/toolchain__pattern-or into-fstar.snap +++ b/test-harness/src/snapshots/toolchain__pattern-or into-fstar.snap @@ -21,9 +21,7 @@ info: backend_options: ~ --- exit = 0 -stderr = ''' -Compiling pattern-or v0.1.0 (WORKSPACE_ROOT/pattern-or) - Finished dev [unoptimized + debuginfo] target(s) in XXs''' +stderr = 'Finished `dev` profile [unoptimized + debuginfo] target(s) in XXs' [stdout] diagnostics = [] @@ -45,4 +43,34 @@ let t_E_cast_to_repr (x: t_E) : isize = | E_B -> isz 1 let bar (x: t_E) : Prims.unit = match x with | E_A | E_B -> () <: Prims.unit + +let deep (x: (i32 & Core.Option.t_Option i32)) : i32 = + match x with + | 1l, Core.Option.Option_Some 3l + | 1l, Core.Option.Option_Some 4l + | 2l, Core.Option.Option_Some 3l + | 2l, Core.Option.Option_Some 4l -> 0l + | x, _ -> x + +let deep_capture (x: Core.Result.t_Result (i32 & i32) (i32 & i32)) : i32 = + match x with + | Core.Result.Result_Ok (1l, x) + | Core.Result.Result_Ok (2l, x) + | Core.Result.Result_Err (3l, x) + | Core.Result.Result_Err (4l, x) -> x + | Core.Result.Result_Ok (x, _) | Core.Result.Result_Err (x, _) -> x + +let equivalent (x: (i32 & Core.Option.t_Option i32)) : i32 = + match x with + | 1l, Core.Option.Option_Some 3l + | 1l, Core.Option.Option_Some 4l + | 2l, Core.Option.Option_Some 3l + | 2l, Core.Option.Option_Some 4l -> 0l + | x, _ -> x + +let nested (x: Core.Option.t_Option i32) : i32 = + match x with + | Core.Option.Option_Some 1l | Core.Option.Option_Some 2l -> 1l + | Core.Option.Option_Some x -> x + | Core.Option.Option_None -> 0l ''' diff --git a/test-harness/src/snapshots/toolchain__recursion into-fstar.snap b/test-harness/src/snapshots/toolchain__recursion into-fstar.snap index 2f2f67f10..00c19c914 100644 --- a/test-harness/src/snapshots/toolchain__recursion into-fstar.snap +++ b/test-harness/src/snapshots/toolchain__recursion into-fstar.snap @@ -21,9 +21,7 @@ info: backend_options: ~ --- exit = 0 -stderr = ''' -Compiling recursion v0.1.0 (WORKSPACE_ROOT/recursion) - Finished dev [unoptimized + debuginfo] target(s) in XXs''' +stderr = 'Finished `dev` profile [unoptimized + debuginfo] target(s) in XXs' [stdout] diagnostics = [] diff --git a/test-harness/src/snapshots/toolchain__side-effects into-fstar.snap b/test-harness/src/snapshots/toolchain__side-effects into-fstar.snap index f99f13441..66de5587a 100644 --- a/test-harness/src/snapshots/toolchain__side-effects into-fstar.snap +++ b/test-harness/src/snapshots/toolchain__side-effects into-fstar.snap @@ -21,9 +21,7 @@ info: backend_options: ~ --- exit = 0 -stderr = ''' -Compiling side-effects v0.1.0 (WORKSPACE_ROOT/side-effects) - Finished dev [unoptimized + debuginfo] target(s) in XXs''' +stderr = 'Finished `dev` profile [unoptimized + debuginfo] target(s) in XXs' [stdout] diagnostics = [] @@ -52,7 +50,9 @@ let direct_result_question_mark_coercion (y: Core.Result.t_Result i8 u16) match y with | Core.Result.Result_Ok hoist1 -> Core.Result.Result_Ok hoist1 <: Core.Result.t_Result i8 u32 | Core.Result.Result_Err err -> - Core.Result.Result_Err (Core.Convert.f_from err) <: Core.Result.t_Result i8 u32 + Core.Result.Result_Err (Core.Convert.f_from #FStar.Tactics.Typeclasses.solve err) + <: + Core.Result.t_Result i8 u32 /// Exercise early returns with control flow and loops let early_returns (x: u32) : u32 = @@ -119,6 +119,7 @@ let local_mutation (x: u32) : u32 = let y:u32 = Core.Iter.Traits.Iterator.f_fold (Core.Iter.Traits.Collect.f_into_iter #(Core.Ops.Range.t_Range u32) + #FStar.Tactics.Typeclasses.solve ({ Core.Ops.Range.f_start = 0ul; Core.Ops.Range.f_end = 10ul } <: Core.Ops.Range.t_Range u32) @@ -272,7 +273,9 @@ let question_mark (x: u32) : Core.Result.t_Result u32 u32 = | Core.Result.Result_Err err -> let! _:Prims.unit = Core.Ops.Control_flow.ControlFlow_Break - (Core.Result.Result_Err (Core.Convert.f_from err) <: Core.Result.t_Result u32 u32) + (Core.Result.Result_Err (Core.Convert.f_from #FStar.Tactics.Typeclasses.solve err) + <: + Core.Result.t_Result u32 u32) <: Core.Ops.Control_flow.t_ControlFlow (Core.Result.t_Result u32 u32) Prims.unit in diff --git a/test-harness/src/snapshots/toolchain__side-effects into-ssprove.snap b/test-harness/src/snapshots/toolchain__side-effects into-ssprove.snap index b2979b525..22288365a 100644 --- a/test-harness/src/snapshots/toolchain__side-effects into-ssprove.snap +++ b/test-harness/src/snapshots/toolchain__side-effects into-ssprove.snap @@ -1,6 +1,5 @@ --- source: test-harness/src/harness.rs -assertion_line: 214 expression: snapshot info: kind: @@ -22,9 +21,7 @@ info: backend_options: ~ --- exit = 0 -stderr = ''' -Compiling side-effects v0.1.0 (WORKSPACE_ROOT/side-effects) - Finished dev [unoptimized + debuginfo] target(s) in XXs''' +stderr = 'Finished `dev` profile [unoptimized + debuginfo] target(s) in XXs' [stdout] diagnostics = [] @@ -117,7 +114,7 @@ Equations local_mutation {L1 : {fset Location}} {I1 : Interface} (x : both L1 I1 letb hoist12 := f_into_iter hoist11 in letb _ := foldi_both_list hoist12 (fun i => ssp (fun _ => - assign todo(term) : (both (*1*)(L1:|:fset [y_loc]) (I1) 'unit))) (ret_both (tt : 'unit)) in + assign todo(term) : (both (*0*)(L1:|:fset []) (I1) 'unit))) (ret_both (tt : 'unit)) in impl__u32__wrapping_add x y else letb hoist15 := matchb x with | 12 => diff --git a/test-harness/src/snapshots/toolchain__slices into-coq.snap b/test-harness/src/snapshots/toolchain__slices into-coq.snap index df241e88f..af66d22c6 100644 --- a/test-harness/src/snapshots/toolchain__slices into-coq.snap +++ b/test-harness/src/snapshots/toolchain__slices into-coq.snap @@ -21,9 +21,7 @@ info: backend_options: ~ --- exit = 0 -stderr = ''' -Compiling slices v0.1.0 (WORKSPACE_ROOT/slices) - Finished dev [unoptimized + debuginfo] target(s) in XXs''' +stderr = 'Finished `dev` profile [unoptimized + debuginfo] target(s) in XXs' [stdout] diagnostics = [] diff --git a/test-harness/src/snapshots/toolchain__slices into-fstar.snap b/test-harness/src/snapshots/toolchain__slices into-fstar.snap index e723cddd9..76ad9ed11 100644 --- a/test-harness/src/snapshots/toolchain__slices into-fstar.snap +++ b/test-harness/src/snapshots/toolchain__slices into-fstar.snap @@ -21,9 +21,7 @@ info: backend_options: ~ --- exit = 0 -stderr = ''' -Compiling slices v0.1.0 (WORKSPACE_ROOT/slices) - Finished dev [unoptimized + debuginfo] target(s) in XXs''' +stderr = 'Finished `dev` profile [unoptimized + debuginfo] target(s) in XXs' [stdout] diagnostics = [] @@ -36,16 +34,18 @@ open Core open FStar.Mul let v_VERSION: t_Slice u8 = - Rust_primitives.unsize (let list = [118uy; 49uy] in - FStar.Pervasives.assert_norm (Prims.eq2 (List.Tot.length list) 2); - Rust_primitives.Hax.array_of_list 2 list) + (let list = [118uy; 49uy] in + FStar.Pervasives.assert_norm (Prims.eq2 (List.Tot.length list) 2); + Rust_primitives.Hax.array_of_list 2 list) + <: + t_Slice u8 let do_something (_: t_Slice u8) : Prims.unit = () let r#unsized (_: t_Array (t_Slice u8) (sz 1)) : Prims.unit = () let sized (x: t_Array (t_Array u8 (sz 4)) (sz 1)) : Prims.unit = - r#unsized (let list = [Rust_primitives.unsize (x.[ sz 0 ] <: t_Array u8 (sz 4)) <: t_Slice u8] in + r#unsized (let list = [x.[ sz 0 ] <: t_Slice u8] in FStar.Pervasives.assert_norm (Prims.eq2 (List.Tot.length list) 1); Rust_primitives.Hax.array_of_list 1 list) ''' diff --git a/test-harness/src/snapshots/toolchain__traits into-fstar.snap b/test-harness/src/snapshots/toolchain__traits into-fstar.snap index 8047ce566..cf3903bb6 100644 --- a/test-harness/src/snapshots/toolchain__traits into-fstar.snap +++ b/test-harness/src/snapshots/toolchain__traits into-fstar.snap @@ -26,6 +26,26 @@ exit = 0 diagnostics = [] [stdout.files] +"Traits.Block_size.fst" = ''' +module Traits.Block_size +#set-options "--fuel 0 --ifuel 1 --z3rlimit 15" +open Core +open FStar.Mul + +class t_BlockSizeUser (v_Self: Type0) = { f_BlockSize:Type0 } + +class t_ParBlocksSizeUser (v_Self: Type0) = { + [@@@ FStar.Tactics.Typeclasses.no_method]_super_10960599340086055385:t_BlockSizeUser v_Self +} + +class t_BlockBackend (v_Self: Type0) = { + [@@@ FStar.Tactics.Typeclasses.no_method]_super_15949286759387124191:t_ParBlocksSizeUser v_Self; + f_proc_block_pre:Alloc.Vec.t_Vec _ Alloc.Alloc.t_Global -> Type0; + f_proc_block_post:Alloc.Vec.t_Vec _ Alloc.Alloc.t_Global -> Prims.unit -> Type0; + f_proc_block:x0: Alloc.Vec.t_Vec _ Alloc.Alloc.t_Global + -> Prims.Pure Prims.unit (f_proc_block_pre x0) (fun result -> f_proc_block_post x0 result) +} +''' "Traits.For_clauses.Issue_495_.Minimized_3_.fst" = ''' module Traits.For_clauses.Issue_495_.Minimized_3_ #set-options "--fuel 0 --ifuel 1 --z3rlimit 15" @@ -50,8 +70,10 @@ let minimized_1_ (list: Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global) : Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global = Core.Iter.Traits.Iterator.f_collect #(Core.Iter.Adapters.Filter.t_Filter (Core.Ops.Range.t_Range u8) (u8 -> bool)) + #FStar.Tactics.Typeclasses.solve #(Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global) (Core.Iter.Traits.Iterator.f_filter #(Core.Ops.Range.t_Range u8) + #FStar.Tactics.Typeclasses.solve ({ Core.Ops.Range.f_start = 0uy; Core.Ops.Range.f_end = 5uy } <: Core.Ops.Range.t_Range u8) (fun temp_0_ -> let _:u8 = temp_0_ in @@ -65,6 +87,7 @@ let minimized_2_ (it: Core.Iter.Adapters.Filter.t_Filter (Core.Ops.Range.t_Range = Core.Iter.Traits.Iterator.f_collect #(Core.Iter.Adapters.Filter.t_Filter (Core.Ops.Range.t_Range u8) (u8 -> bool)) + #FStar.Tactics.Typeclasses.solve #(Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global) it in @@ -75,16 +98,21 @@ let original_function_from_495_ (list: Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global) = Core.Iter.Traits.Iterator.f_collect #(Core.Iter.Adapters.Filter.t_Filter (Core.Ops.Range.t_Range u8) (u8 -> bool)) + #FStar.Tactics.Typeclasses.solve #(Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global) (Core.Iter.Traits.Iterator.f_filter #(Core.Ops.Range.t_Range u8) + #FStar.Tactics.Typeclasses.solve ({ Core.Ops.Range.f_start = 0uy; Core.Ops.Range.f_end = 5uy } <: Core.Ops.Range.t_Range u8 ) (fun i -> let i:u8 = i in let _, out:(Core.Slice.Iter.t_Iter u8 & bool) = Core.Iter.Traits.Iterator.f_any #(Core.Slice.Iter.t_Iter u8) + #FStar.Tactics.Typeclasses.solve (Core.Slice.impl__iter #u8 - (Core.Ops.Deref.f_deref #(Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global) list + (Core.Ops.Deref.f_deref #(Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global) + #FStar.Tactics.Typeclasses.solve + list <: t_Slice u8) <: @@ -106,14 +134,14 @@ open Core open FStar.Mul class t_Foo (v_Self: Type0) (v_T: Type0) = { - f_to_t_pre:v_Self -> bool; - f_to_t_post:v_Self -> v_T -> bool; + f_to_t_pre:v_Self -> Type0; + f_to_t_post:v_Self -> v_T -> Type0; f_to_t:x0: v_Self -> Prims.Pure v_T (f_to_t_pre x0) (fun result -> f_to_t_post x0 result) } let v__f (#v_X: Type0) (#[FStar.Tactics.Typeclasses.tcresolve ()] i1: t_Foo v_X u8) (x: v_X) : Prims.unit = - let _:u8 = f_to_t #v_X #u8 x in + let _:u8 = f_to_t #v_X #u8 #FStar.Tactics.Typeclasses.solve x in () ''' "Traits.Implicit_dependencies_issue_667_.Define_type.fst" = ''' @@ -151,8 +179,8 @@ open Core open FStar.Mul class t_MyTrait (v_Self: Type0) = { - f_my_method_pre:v_Self -> bool; - f_my_method_post:v_Self -> Prims.unit -> bool; + f_my_method_pre:v_Self -> Type0; + f_my_method_post:v_Self -> Prims.unit -> Type0; f_my_method:x0: v_Self -> Prims.Pure Prims.unit (f_my_method_pre x0) (fun result -> f_my_method_post x0 result) } @@ -171,8 +199,278 @@ let _ = let some_function (x: Traits.Implicit_dependencies_issue_667_.Define_type.t_MyType) : Prims.unit = Traits.Implicit_dependencies_issue_667_.Trait_definition.f_my_method #Traits.Implicit_dependencies_issue_667_.Define_type.t_MyType + #FStar.Tactics.Typeclasses.solve x ''' +"Traits.Implicit_explicit_calling_conventions.fst" = ''' +module Traits.Implicit_explicit_calling_conventions +#set-options "--fuel 0 --ifuel 1 --z3rlimit 15" +open Core +open FStar.Mul + +type t_Type (v_TypeArg: Type0) (v_ConstArg: usize) = { f_field:t_Array v_TypeArg v_ConstArg } + +class t_Trait (v_Self: Type0) (v_TypeArg: Type0) (v_ConstArg: usize) = { + f_method_pre: + #v_MethodTypeArg: Type0 -> + v_MethodConstArg: usize -> + v_Self -> + v_TypeArg -> + t_Type v_TypeArg v_ConstArg + -> Type0; + f_method_post: + #v_MethodTypeArg: Type0 -> + v_MethodConstArg: usize -> + v_Self -> + v_TypeArg -> + t_Type v_TypeArg v_ConstArg -> + Prims.unit + -> Type0; + f_method: + #v_MethodTypeArg: Type0 -> + v_MethodConstArg: usize -> + x0: v_Self -> + x1: v_TypeArg -> + x2: t_Type v_TypeArg v_ConstArg + -> Prims.Pure Prims.unit + (f_method_pre #v_MethodTypeArg v_MethodConstArg x0 x1 x2) + (fun result -> f_method_post #v_MethodTypeArg v_MethodConstArg x0 x1 x2 result); + f_associated_function_pre: + #v_MethodTypeArg: Type0 -> + v_MethodConstArg: usize -> + v_Self -> + v_TypeArg -> + t_Type v_TypeArg v_ConstArg + -> Type0; + f_associated_function_post: + #v_MethodTypeArg: Type0 -> + v_MethodConstArg: usize -> + v_Self -> + v_TypeArg -> + t_Type v_TypeArg v_ConstArg -> + Prims.unit + -> Type0; + f_associated_function: + #v_MethodTypeArg: Type0 -> + v_MethodConstArg: usize -> + x0: v_Self -> + x1: v_TypeArg -> + x2: t_Type v_TypeArg v_ConstArg + -> Prims.Pure Prims.unit + (f_associated_function_pre #v_MethodTypeArg v_MethodConstArg x0 x1 x2) + (fun result -> f_associated_function_post #v_MethodTypeArg v_MethodConstArg x0 x1 x2 result) +} + +[@@ FStar.Tactics.Typeclasses.tcinstance] +let impl (#v_TypeArg: Type0) (v_ConstArg: usize) : t_Trait Prims.unit v_TypeArg v_ConstArg = + { + f_method_pre + = + (fun + (#v_MethodTypeArg: Type0) + (v_MethodConstArg: usize) + (self: Prims.unit) + (value_TypeArg: v_TypeArg) + (value_Type: t_Type v_TypeArg v_ConstArg) + -> + true); + f_method_post + = + (fun + (#v_MethodTypeArg: Type0) + (v_MethodConstArg: usize) + (self: Prims.unit) + (value_TypeArg: v_TypeArg) + (value_Type: t_Type v_TypeArg v_ConstArg) + (out: Prims.unit) + -> + true); + f_method + = + (fun + (#v_MethodTypeArg: Type0) + (v_MethodConstArg: usize) + (self: Prims.unit) + (value_TypeArg: v_TypeArg) + (value_Type: t_Type v_TypeArg v_ConstArg) + -> + ()); + f_associated_function_pre + = + (fun + (#v_MethodTypeArg: Type0) + (v_MethodConstArg: usize) + (v__self: Prims.unit) + (value_TypeArg: v_TypeArg) + (value_Type: t_Type v_TypeArg v_ConstArg) + -> + true); + f_associated_function_post + = + (fun + (#v_MethodTypeArg: Type0) + (v_MethodConstArg: usize) + (v__self: Prims.unit) + (value_TypeArg: v_TypeArg) + (value_Type: t_Type v_TypeArg v_ConstArg) + (out: Prims.unit) + -> + true); + f_associated_function + = + fun + (#v_MethodTypeArg: Type0) + (v_MethodConstArg: usize) + (v__self: Prims.unit) + (value_TypeArg: v_TypeArg) + (value_Type: t_Type v_TypeArg v_ConstArg) + -> + () + } + +class t_SubTrait (v_Self: Type0) (v_TypeArg: Type0) (v_ConstArg: usize) = { + [@@@ FStar.Tactics.Typeclasses.no_method]_super_2645671271498264788:t_Trait v_Self + v_TypeArg + v_ConstArg; + f_AssocType:Type0; + f_AssocType_1171953828677564027:t_Trait f_AssocType v_TypeArg v_ConstArg +} + +let associated_function_caller + (#v_MethodTypeArg #v_TypeArg: Type0) + (v_ConstArg v_MethodConstArg: usize) + (#v_ImplTrait: Type0) + (#[FStar.Tactics.Typeclasses.tcresolve ()] i3: t_Trait v_ImplTrait v_TypeArg v_ConstArg) + (x: v_ImplTrait) + (value_TypeArg: v_TypeArg) + (value_Type: t_Type v_TypeArg v_ConstArg) + : Prims.unit = + let _:Prims.unit = + f_associated_function #v_ImplTrait + #v_TypeArg + #v_ConstArg + #FStar.Tactics.Typeclasses.solve + #v_MethodTypeArg + v_MethodConstArg + x + value_TypeArg + value_Type + in + () + +let method_caller + (#v_MethodTypeArg #v_TypeArg: Type0) + (v_ConstArg v_MethodConstArg: usize) + (#v_ImplTrait: Type0) + (#[FStar.Tactics.Typeclasses.tcresolve ()] i3: t_Trait v_ImplTrait v_TypeArg v_ConstArg) + (x: v_ImplTrait) + (value_TypeArg: v_TypeArg) + (value_Type: t_Type v_TypeArg v_ConstArg) + : Prims.unit = + let _:Prims.unit = + f_method #v_ImplTrait + #v_TypeArg + #v_ConstArg + #FStar.Tactics.Typeclasses.solve + #v_MethodTypeArg + v_MethodConstArg + x + value_TypeArg + value_Type + in + () +''' +"Traits.Interlaced_consts_types.fst" = ''' +module Traits.Interlaced_consts_types +#set-options "--fuel 0 --ifuel 1 --z3rlimit 15" +open Core +open FStar.Mul + +class t_Foo (v_Self: Type0) (v_FooConst: usize) (v_FooType: Type0) = { + f_fun_pre: + v_FunConst: usize -> + #v_FunType: Type0 -> + t_Array v_FooType v_FooConst -> + t_Array v_FunType v_FunConst + -> Type0; + f_fun_post: + v_FunConst: usize -> + #v_FunType: Type0 -> + t_Array v_FooType v_FooConst -> + t_Array v_FunType v_FunConst -> + Prims.unit + -> Type0; + f_fun: + v_FunConst: usize -> + #v_FunType: Type0 -> + x0: t_Array v_FooType v_FooConst -> + x1: t_Array v_FunType v_FunConst + -> Prims.Pure Prims.unit + (f_fun_pre v_FunConst #v_FunType x0 x1) + (fun result -> f_fun_post v_FunConst #v_FunType x0 x1 result) +} + +[@@ FStar.Tactics.Typeclasses.tcinstance] +let impl (v_FooConst: usize) (#v_FooType #v_SelfType: Type0) : t_Foo v_SelfType v_FooConst v_FooType = + { + f_fun_pre + = + (fun + (v_FunConst: usize) + (#v_FunType: Type0) + (x: t_Array v_FooType v_FooConst) + (y: t_Array v_FunType v_FunConst) + -> + true); + f_fun_post + = + (fun + (v_FunConst: usize) + (#v_FunType: Type0) + (x: t_Array v_FooType v_FooConst) + (y: t_Array v_FunType v_FunConst) + (out: Prims.unit) + -> + true); + f_fun + = + fun + (v_FunConst: usize) + (#v_FunType: Type0) + (x: t_Array v_FooType v_FooConst) + (y: t_Array v_FunType v_FunConst) + -> + () + } + +type t_Bar (v_FooConst: usize) (v_FooType: Type0) = + | Bar : t_Array v_FooType v_FooConst -> t_Bar v_FooConst v_FooType +''' +"Traits.Recursive_trait_with_assoc_type.fst" = ''' +module Traits.Recursive_trait_with_assoc_type +#set-options "--fuel 0 --ifuel 1 --z3rlimit 15" +open Core +open FStar.Mul + +class t_Trait1 (v_Self: Type0) = { + f_T:Type0; + f_T_14152278567792570575:t_Trait1 f_T +} + +class t_Trait2 (v_Self: Type0) = { + [@@@ FStar.Tactics.Typeclasses.no_method]_super_4567617955834163411:t_Trait1 v_Self; + f_U:Type0 +} +''' +"Traits.Type_alias_bounds_issue_707_.fst" = ''' +module Traits.Type_alias_bounds_issue_707_ +#set-options "--fuel 0 --ifuel 1 --z3rlimit 15" +open Core +open FStar.Mul + +type t_StructWithGenericBounds (v_T: Type0) {| i1: Core.Clone.t_Clone v_T |} = + | StructWithGenericBounds : v_T -> t_StructWithGenericBounds v_T +''' "Traits.Unconstrainted_types_issue_677_.fst" = ''' module Traits.Unconstrainted_types_issue_677_ #set-options "--fuel 0 --ifuel 1 --z3rlimit 15" @@ -180,13 +478,13 @@ open Core open FStar.Mul class t_PolyOp (v_Self: Type0) = { - f_op_pre:u32 -> u32 -> bool; - f_op_post:u32 -> u32 -> u32 -> bool; + f_op_pre:u32 -> u32 -> Type0; + f_op_post:u32 -> u32 -> u32 -> Type0; f_op:x0: u32 -> x1: u32 -> Prims.Pure u32 (f_op_pre x0 x1) (fun result -> f_op_post x0 x1 result) } let twice (#v_OP: Type0) (#[FStar.Tactics.Typeclasses.tcresolve ()] i1: t_PolyOp v_OP) (x: u32) - : u32 = f_op #v_OP x x + : u32 = f_op #v_OP #FStar.Tactics.Typeclasses.solve x x type t_Plus = | Plus : t_Plus @@ -217,13 +515,13 @@ open Core open FStar.Mul class t_Bar (v_Self: Type0) = { - f_bar_pre:v_Self -> bool; - f_bar_post:v_Self -> Prims.unit -> bool; + f_bar_pre:v_Self -> Type0; + f_bar_post:v_Self -> Prims.unit -> Type0; f_bar:x0: v_Self -> Prims.Pure Prims.unit (f_bar_pre x0) (fun result -> f_bar_post x0 result) } let impl_2__method (#v_T: Type0) (#[FStar.Tactics.Typeclasses.tcresolve ()] i1: t_Bar v_T) (x: v_T) - : Prims.unit = f_bar #v_T x + : Prims.unit = f_bar #v_T #FStar.Tactics.Typeclasses.solve x type t_Error = | Error_Fail : t_Error @@ -236,16 +534,16 @@ let t_Error_cast_to_repr (x: t_Error) : isize = match x with | Error_Fail -> is class t_Lang (v_Self: Type0) = { f_Var:Type0; - f_s_pre:v_Self -> i32 -> bool; - f_s_post:v_Self -> i32 -> (v_Self & f_Var) -> bool; + f_s_pre:v_Self -> i32 -> Type0; + f_s_post:v_Self -> i32 -> (v_Self & f_Var) -> Type0; f_s:x0: v_Self -> x1: i32 -> Prims.Pure (v_Self & f_Var) (f_s_pre x0 x1) (fun result -> f_s_post x0 x1 result) } class t_SuperTrait (v_Self: Type0) = { [@@@ FStar.Tactics.Typeclasses.no_method]_super_9442900250278684536:Core.Clone.t_Clone v_Self; - f_function_of_super_trait_pre:v_Self -> bool; - f_function_of_super_trait_post:v_Self -> u32 -> bool; + f_function_of_super_trait_pre:v_Self -> Type0; + f_function_of_super_trait_post:v_Self -> u32 -> Type0; f_function_of_super_trait:x0: v_Self -> Prims.Pure u32 (f_function_of_super_trait_pre x0) @@ -263,21 +561,23 @@ let impl_SuperTrait_for_i32: t_SuperTrait i32 = class t_Foo (v_Self: Type0) = { f_AssocType:Type0; - f_AssocType_17663802186765685673:t_SuperTrait f_AssocType; - f_AssocType_10139459042277121690:Core.Clone.t_Clone f_AssocType; + f_AssocType_9316156492785325993:t_SuperTrait f_AssocType; + f_AssocType_11693383309247349160:Core.Clone.t_Clone f_AssocType; f_N:usize; - f_assoc_f_pre:Prims.unit -> bool; - f_assoc_f_post:Prims.unit -> Prims.unit -> bool; + f_assoc_f_pre:Prims.unit -> Type0; + f_assoc_f_post:Prims.unit -> Prims.unit -> Type0; f_assoc_f:x0: Prims.unit -> Prims.Pure Prims.unit (f_assoc_f_pre x0) (fun result -> f_assoc_f_post x0 result); - f_method_f_pre:v_Self -> bool; - f_method_f_post:v_Self -> Prims.unit -> bool; + f_method_f_pre:v_Self -> Type0; + f_method_f_post:v_Self -> Prims.unit -> Type0; f_method_f:x0: v_Self -> Prims.Pure Prims.unit (f_method_f_pre x0) (fun result -> f_method_f_post x0 result); - f_assoc_type_pre:{| i3: Core.Marker.t_Copy f_AssocType |} -> f_AssocType -> bool; - f_assoc_type_post:{| i3: Core.Marker.t_Copy f_AssocType |} -> f_AssocType -> Prims.unit -> bool; + f_assoc_type_pre:{| i3: Core.Marker.t_Copy f_AssocType |} -> f_AssocType -> Type0; + f_assoc_type_post:{| i3: Core.Marker.t_Copy f_AssocType |} -> f_AssocType -> Prims.unit -> Type0; f_assoc_type:{| i3: Core.Marker.t_Copy f_AssocType |} -> x0: f_AssocType - -> Prims.Pure Prims.unit (f_assoc_type_pre i3 x0) (fun result -> f_assoc_type_post i3 x0 result) + -> Prims.Pure Prims.unit + (f_assoc_type_pre #i3 x0) + (fun result -> f_assoc_type_post #i3 x0 result) } let closure_impl_expr @@ -286,8 +586,13 @@ let closure_impl_expr (it: v_I) : Alloc.Vec.t_Vec Prims.unit Alloc.Alloc.t_Global = Core.Iter.Traits.Iterator.f_collect #(Core.Iter.Adapters.Map.t_Map v_I (Prims.unit -> Prims.unit)) + #FStar.Tactics.Typeclasses.solve #(Alloc.Vec.t_Vec Prims.unit Alloc.Alloc.t_Global) - (Core.Iter.Traits.Iterator.f_map #v_I #Prims.unit it (fun x -> x) + (Core.Iter.Traits.Iterator.f_map #v_I + #FStar.Tactics.Typeclasses.solve + #Prims.unit + it + (fun x -> x) <: Core.Iter.Adapters.Map.t_Map v_I (Prims.unit -> Prims.unit)) @@ -299,30 +604,33 @@ let closure_impl_expr_fngen (f: v_F) : Alloc.Vec.t_Vec Prims.unit Alloc.Alloc.t_Global = Core.Iter.Traits.Iterator.f_collect #(Core.Iter.Adapters.Map.t_Map v_I v_F) + #FStar.Tactics.Typeclasses.solve #(Alloc.Vec.t_Vec Prims.unit Alloc.Alloc.t_Global) - (Core.Iter.Traits.Iterator.f_map #v_I #Prims.unit #v_F it f + (Core.Iter.Traits.Iterator.f_map #v_I #FStar.Tactics.Typeclasses.solve #Prims.unit #v_F it f <: Core.Iter.Adapters.Map.t_Map v_I v_F) let f (#v_T: Type0) (#[FStar.Tactics.Typeclasses.tcresolve ()] i1: t_Foo v_T) (x: v_T) : Prims.unit = - let _:Prims.unit = f_assoc_f #v_T () in - f_method_f #v_T x + let _:Prims.unit = f_assoc_f #v_T #FStar.Tactics.Typeclasses.solve () in + f_method_f #v_T #FStar.Tactics.Typeclasses.solve x let g (#v_T: Type0) (#[FStar.Tactics.Typeclasses.tcresolve ()] i1: t_Foo v_T) (x: i1.f_AssocType) - : u32 = f_function_of_super_trait #i1.f_AssocType x + : u32 = f_function_of_super_trait #i1.f_AssocType #FStar.Tactics.Typeclasses.solve x [@@ FStar.Tactics.Typeclasses.tcinstance] let impl_Foo_for_tuple_: t_Foo Prims.unit = { f_AssocType = i32; - f_AssocType_17663802186765685673 = FStar.Tactics.Typeclasses.solve; + f_AssocType_9316156492785325993 = FStar.Tactics.Typeclasses.solve; f_N = sz 32; f_assoc_f_pre = (fun (_: Prims.unit) -> true); f_assoc_f_post = (fun (_: Prims.unit) (out: Prims.unit) -> true); f_assoc_f = (fun (_: Prims.unit) -> () <: Prims.unit); f_method_f_pre = (fun (self: Prims.unit) -> true); f_method_f_post = (fun (self: Prims.unit) (out: Prims.unit) -> true); - f_method_f = (fun (self: Prims.unit) -> f_assoc_f #Prims.unit ()); + f_method_f + = + (fun (self: Prims.unit) -> f_assoc_f #Prims.unit #FStar.Tactics.Typeclasses.solve ()); f_assoc_type_pre = (fun (_: i32) -> true); f_assoc_type_post = (fun (_: i32) (out: Prims.unit) -> true); f_assoc_type = fun (_: i32) -> () diff --git a/test-harness/src/snapshots/toolchain__v1-lib lint-hacspec.snap b/test-harness/src/snapshots/toolchain__v1-lib lint-hacspec.snap deleted file mode 100644 index 67c48fc48..000000000 --- a/test-harness/src/snapshots/toolchain__v1-lib lint-hacspec.snap +++ /dev/null @@ -1,25 +0,0 @@ ---- -source: test-harness/src/harness.rs -expression: snapshot -info: - kind: - Lint: - linter: hacspec - info: - name: v1-lib - manifest: lint/hacspec/v1-lib/Cargo.toml - description: ~ - spec: - optional: false - broken: false - issue_id: ~ - positive: true - snapshot: - stderr: true - stdout: true ---- -exit = 0 -stderr = ''' -Compiling v1-lib v0.1.0 (WORKSPACE_ROOT/lint/hacspec/v1-lib) - Finished dev [unoptimized + debuginfo] target(s) in XXs''' -stdout = '' diff --git a/tests/Cargo.lock b/tests/Cargo.lock index 69afac770..d3d491045 100644 --- a/tests/Cargo.lock +++ b/tests/Cargo.lock @@ -26,6 +26,10 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" +[[package]] +name = "assert" +version = "0.1.0" + [[package]] name = "attribute-opaque" version = "0.1.0" @@ -213,6 +217,10 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "dyn" +version = "0.1.0" + [[package]] name = "either" version = "1.9.0" @@ -236,8 +244,11 @@ name = "fn-to-letfun" version = "0.1.0" [[package]] -name = "fnmut" +name = "functions" version = "0.1.0" +dependencies = [ + "hax-lib", +] [[package]] name = "generics" @@ -256,6 +267,13 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "guards" +version = "0.1.0" +dependencies = [ + "hax-lib", +] + [[package]] name = "hacspec-dev" version = "0.1.0-beta.1" @@ -304,6 +322,7 @@ name = "hax-lib-macros" version = "0.1.0-pre.1" dependencies = [ "hax-lib-macros-types", + "paste", "proc-macro-error", "proc-macro2", "quote", @@ -412,6 +431,10 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +[[package]] +name = "let-else" +version = "0.1.0" + [[package]] name = "libc" version = "0.2.147" @@ -476,6 +499,9 @@ checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "loops" version = "0.1.0" +dependencies = [ + "hax-lib", +] [[package]] name = "memchr" @@ -491,10 +517,6 @@ version = "0.1.0" name = "mut-ref-functionalization" version = "0.1.0" -[[package]] -name = "mut_arg" -version = "0.1.0" - [[package]] name = "naming" version = "0.1.0" @@ -623,6 +645,12 @@ version = "6.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + [[package]] name = "pattern-or" version = "0.1.0" @@ -922,13 +950,6 @@ dependencies = [ "getrandom", ] -[[package]] -name = "v1-lib" -version = "0.1.0" -dependencies = [ - "hacspec-lib", -] - [[package]] name = "version_check" version = "0.9.4" diff --git a/tests/Cargo.toml b/tests/Cargo.toml index 8dd33e0b7..e4e1ef280 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -1,16 +1,15 @@ [workspace] members = [ + "assert", "enum-struct-variant", "literals", "slices", "naming", "if-let", + "let-else", "enum-repr", "pattern-or", "side-effects", - "lint/hacspec/v1-lib", - "lint/hacspec/mut_args", - "lint/rust/fnmut", "mut-ref-functionalization", "generics", "loops", @@ -21,6 +20,7 @@ members = [ "attribute-opaque", "raw-attributes", "traits", + "dyn", "reordering", "nested-derefs", "proverif-minimal", @@ -31,5 +31,7 @@ members = [ "cli/include-flag", "cli/interface-only", "recursion", + "functions", + "guards", ] resolver = "2" diff --git a/tests/assert/Cargo.toml b/tests/assert/Cargo.toml new file mode 100644 index 000000000..bbc1c555a --- /dev/null +++ b/tests/assert/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "assert" +version = "0.1.0" +edition = "2021" + +[dependencies] + +[package.metadata.hax-tests] +into."fstar+coq+ssprove" = { broken = false, snapshot = "stdout", issue_id = "285" } diff --git a/tests/assert/src/lib.rs b/tests/assert/src/lib.rs new file mode 100644 index 000000000..0c1298433 --- /dev/null +++ b/tests/assert/src/lib.rs @@ -0,0 +1,10 @@ +#![allow(dead_code)] + +pub fn asserts() { + assert!({ + assert!(true); + 1 == 1 + }); + assert_eq!(2, 2); + assert_ne!(1, 2); +} diff --git a/tests/attributes/src/lib.rs b/tests/attributes/src/lib.rs index aa40cc7d3..181057d2f 100644 --- a/tests/attributes/src/lib.rs +++ b/tests/attributes/src/lib.rs @@ -11,6 +11,30 @@ fn add3(x: u32, y: u32, z: u32) -> u32 { x + y + z } +#[hax::requires(*x < 40 && *y < 300)] +#[hax::ensures(|result| *future(x) == *y && *future(y) == *x && result == *x + *y)] +fn swap_and_mut_req_ens(x: &mut u32, y: &mut u32) -> u32 { + let x0 = *x; + *x = *y; + *y = x0; + *x + *y +} + +#[hax_lib::ensures(|_| true)] +fn issue_844(_x: &mut u8) {} + +// From issue #845 +mod ensures_on_arity_zero_fns { + #[hax_lib::requires(true)] + #[hax_lib::ensures(|_x| true)] + fn doing_nothing() {} + #[hax_lib::requires(true)] + #[hax_lib::ensures(|x| x > 100)] + fn basically_a_constant() -> u8 { + 127 + } +} + #[hax::lemma] fn add3_lemma(x: u32) -> Proof<{ x <= 10 || x >= u32_max / 3 || add3(x, x, x) == x * 3 }> {} @@ -148,6 +172,50 @@ fn some_function() -> String { String::from("hello from Rust") } +mod pre_post_on_traits_and_impls { + use hax_lib::int::*; + + #[hax_lib::attributes] + trait Operation { + // we allow `hax_lib`, `::hax_lib` or no path at all + #[hax_lib::requires(x.lift() <= int!(127))] + #[ensures(|result| x.lift() * int!(2) == result.lift())] + fn double(x: u8) -> u8; + } + + struct ViaAdd; + struct ViaMul; + + #[hax_lib::attributes] + impl Operation for ViaAdd { + #[::hax_lib::requires(x.lift() <= int!(127))] + #[ensures(|result| x.lift() * int!(2) == result.lift())] + fn double(x: u8) -> u8 { + x + x + } + } + + #[hax_lib::attributes] + impl Operation for ViaMul { + #[requires(x.lift() <= int!(127))] + #[::hax_lib::ensures(|result| x.lift() * int!(2) == result.lift())] + fn double(x: u8) -> u8 { + x * 2 + } + } + + #[hax_lib::attributes] + trait TraitWithRequiresAndEnsures { + #[requires(x < 100)] + #[ensures(|r| r > 88)] + fn method(&self, x: u8) -> u8; + } + + fn test(x: T) -> u8 { + x.method(99) - 88 + } +} + /// An minimal example of a model of math integers for F* mod int_model { use super::hax; @@ -223,3 +291,50 @@ mod refinement_types { #[hax_lib::refinement_type(|x| x == 4 || x == 5 || x == 10 || x == 11)] pub struct CompressionFactor(u8); } +mod nested_refinement_elim { + use hax_lib::*; + #[refinement_type(|x| true)] + pub struct DummyRefinement(u16); + + fn elim_twice(x: DummyRefinement) -> u16 { + (DummyRefinement::new(x.get())).get() + } +} + +/// `ensures` and `requires` with inlined code (issue #825) +mod inlined_code_ensures_requires { + #[hax_lib::requires(fstar!("forall i. FStar.Seq.index $v i <. ${254u8}"))] + #[hax_lib::ensures(|()| { + let future_v = future(v); + fstar!("forall i. FStar.Seq.index ${future_v} i >. ${0u8}") + })] + fn increment_array(v: &mut [u8; 4]) { + v[0] += 1; + v[1] += 1; + v[2] += 1; + v[3] += 1; + } +} + +mod verifcation_status { + #[hax_lib::fstar::verification_status(lax)] + fn a_function_which_only_laxes() { + assert!(/*very complicated stuff*/ false) + } + + #[hax_lib::fstar::verification_status(panic_free)] + #[hax_lib::ensures(|x|/*very complicated stuff*/false)] + fn a_panicfree_function() -> u8 { + let a = 3; + let b = 6; + a + b + } + + #[hax_lib::fstar::verification_status(panic_free)] + #[hax_lib::ensures(|x|/*very complicated stuff*/false)] + fn another_panicfree_function() { + let not_much = 0; + let nothing = 0; + let still_not_much = not_much + nothing; + } +} diff --git a/tests/dyn/Cargo.toml b/tests/dyn/Cargo.toml new file mode 100644 index 000000000..84580c524 --- /dev/null +++ b/tests/dyn/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "dyn" +version = "0.1.0" +edition = "2021" + +[dependencies] + +[package.metadata.hax-tests] +into."fstar" = { broken = false, snapshot = "stdout", issue_id = "296" } diff --git a/tests/dyn/src/lib.rs b/tests/dyn/src/lib.rs new file mode 100644 index 000000000..37ee4fb28 --- /dev/null +++ b/tests/dyn/src/lib.rs @@ -0,0 +1,15 @@ +#![allow(dead_code)] + +pub trait Printable { + fn stringify(&self) -> S; +} + +impl Printable for i32 { + fn stringify(&self) -> String { + self.to_string() + } +} + +pub fn print(a: Box>) { + println!("{}", a.stringify()); +} diff --git a/tests/functions/Cargo.toml b/tests/functions/Cargo.toml new file mode 100644 index 000000000..215bd726c --- /dev/null +++ b/tests/functions/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "functions" +version = "0.1.0" +edition = "2021" + +[dependencies] +hax-lib = { path = "../../hax-lib" } + +[package.metadata.hax-tests] +into."fstar+coq" = { snapshot = "stdout" } diff --git a/tests/functions/src/lib.rs b/tests/functions/src/lib.rs new file mode 100644 index 000000000..f3c4b4801 --- /dev/null +++ b/tests/functions/src/lib.rs @@ -0,0 +1,6 @@ +/// Issue #757 +fn calling_function_pointer() { + fn f() {} + let f_ptr = f::; + f_ptr(); +} diff --git a/tests/guards/Cargo.toml b/tests/guards/Cargo.toml new file mode 100644 index 000000000..4f49f1abc --- /dev/null +++ b/tests/guards/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "guards" +version = "0.1.0" +edition = "2021" + +[dependencies] +hax-lib = { path = "../../hax-lib" } + +[package.metadata.hax-tests] +into."fstar+coq+ssprove" = { broken = false, snapshot = "stdout", issue_id = "814" } diff --git a/tests/guards/src/lib.rs b/tests/guards/src/lib.rs new file mode 100644 index 000000000..a836396f0 --- /dev/null +++ b/tests/guards/src/lib.rs @@ -0,0 +1,47 @@ +#![feature(if_let_guard)] +#![allow(dead_code)] + +pub fn if_let_guard(x: Option>) -> i32 { + match x { + None => 0, + Some(v) if let Ok(y) = v => y, + Some(Err(y)) => y, + _ => 1, + } +} + +pub fn equivalent(x: Option>) -> i32 { + match x { + None => 0, + _ => match match x { + Some(v) => match v { + Ok(y) => Some(y), + _ => None, + }, + _ => None, + } { + Some(y) => y, + None => match x { + Some(Err(y)) => y, + _ => 1, + }, + }, + } +} + +pub fn multiple_guards(x: Option>) -> i32 { + match x { + None => 0, + Some(Ok(v)) if let Some(1) = Some(v + 1) => 0, + Some(v) if let Ok(y) = v => y, + Some(Err(y)) => y, + _ => 1, + } +} + +pub fn if_guard(x: Option) -> i32 { + match x { + Some(v) if v > 0 => v, + _ => 0, + } +} diff --git a/tests/let-else/Cargo.toml b/tests/let-else/Cargo.toml new file mode 100644 index 000000000..bb5cd3d8b --- /dev/null +++ b/tests/let-else/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "let-else" +version = "0.1.0" +edition = "2021" + +[dependencies] + +[package.metadata.hax-tests] +into."fstar+coq+ssprove" = { broken = false, snapshot = "stdout", issue_id = "155" } diff --git a/tests/let-else/src/lib.rs b/tests/let-else/src/lib.rs new file mode 100644 index 000000000..c040d1c07 --- /dev/null +++ b/tests/let-else/src/lib.rs @@ -0,0 +1,13 @@ +#![allow(dead_code)] + +pub fn let_else(opt: Option) -> bool { + let Some(x) = opt else { return false }; + true +} + +pub fn let_else_different_type(opt: Option) -> bool { + let_else({ + let Some(x) = opt else { return false }; + Some(x + 1) + }) +} diff --git a/tests/lint/hacspec/mut_args/Cargo.toml b/tests/lint/hacspec/mut_args/Cargo.toml deleted file mode 100644 index 130f2fb6d..000000000 --- a/tests/lint/hacspec/mut_args/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "mut_arg" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] - -[package.metadata.hax-tests.lint.hacspec] diff --git a/tests/lint/hacspec/mut_args/src/lib.rs b/tests/lint/hacspec/mut_args/src/lib.rs deleted file mode 100644 index 418fbec0e..000000000 --- a/tests/lint/hacspec/mut_args/src/lib.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub fn add(left: &mut usize, right: usize) { - *left += right -} diff --git a/tests/lint/hacspec/v1-lib/Cargo.toml b/tests/lint/hacspec/v1-lib/Cargo.toml deleted file mode 100644 index 3ed25fbd9..000000000 --- a/tests/lint/hacspec/v1-lib/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "v1-lib" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -hacspec-lib = { git = "https://github.com/hacspec/hacspec.git" } - -[package.metadata.hax-tests.lint.hacspec] diff --git a/tests/lint/hacspec/v1-lib/src/lib.rs b/tests/lint/hacspec/v1-lib/src/lib.rs deleted file mode 100644 index a9a12ae08..000000000 --- a/tests/lint/hacspec/v1-lib/src/lib.rs +++ /dev/null @@ -1,18 +0,0 @@ -use hacspec_lib::*; - -bytes!(MyBytes, 8); -array!(State, 16, U32, type_for_indexes: StateIdx); - -public_nat_mod!( - type_name: PublicX25519FieldElement, - type_of_canvas: PublicFieldCanvas, - bit_size_of_field: 256, - modulo_value: "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed" -); - -nat_mod!( - type_name: X25519FieldElement, - type_of_canvas: FieldCanvas, - bit_size_of_field: 256, - modulo_value: "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed" -); diff --git a/tests/lint/rust/fnmut/Cargo.toml b/tests/lint/rust/fnmut/Cargo.toml deleted file mode 100644 index 9bfb81724..000000000 --- a/tests/lint/rust/fnmut/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "fnmut" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] - -[package.metadata.hax-tests.lint.rust] diff --git a/tests/lint/rust/fnmut/src/lib.rs b/tests/lint/rust/fnmut/src/lib.rs deleted file mode 100644 index e2e1f3046..000000000 --- a/tests/lint/rust/fnmut/src/lib.rs +++ /dev/null @@ -1,20 +0,0 @@ -//! Tests for the Rust linter -//! -//! No FnMut - -trait SomeTrait { - fn update_fun(&self, fun: F) -> u8 - where - F: FnMut(u32) -> u8; -} - -struct UpdatableStruct {} - -impl SomeTrait for UpdatableStruct { - fn update_fun(&self, mut fun: F) -> u8 - where - F: FnMut(u32) -> u8, - { - fun(123) - } -} diff --git a/tests/loops/Cargo.toml b/tests/loops/Cargo.toml index a6139c47a..96dfe7dc3 100644 --- a/tests/loops/Cargo.toml +++ b/tests/loops/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] +hax-lib = { path = "../../hax-lib" } [package.metadata.hax-tests] into."fstar" = { } diff --git a/tests/loops/src/lib.rs b/tests/loops/src/lib.rs index 22ee1cab6..7c209eee1 100644 --- a/tests/loops/src/lib.rs +++ b/tests/loops/src/lib.rs @@ -1,3 +1,34 @@ +mod recognized_loops { + fn range() { + let mut count = 0u64; + for i in 0u8..10u8 { + hax_lib::loop_invariant!(|i: u8| i <= 10); + count += 1; + } + } + fn range_step_by() { + let mut count = 0u64; + for i in (0u8..10u8).step_by(2) { + hax_lib::loop_invariant!(|i: u8| i <= 10); + count += 1; + } + } + fn enumerated_slice(slice: &[T]) { + let mut count = 0u64; + for i in slice.into_iter().enumerate() { + hax_lib::loop_invariant!(|i: usize| i <= 10); + count += 2; + } + } + fn enumerated_chunked_slice(slice: &[T]) { + let mut count = 0u64; + for i in slice.chunks_exact(3).enumerate() { + hax_lib::loop_invariant!(|i: usize| { fstar!("$i <= ${slice.len()}") }); + count += 3; + } + } +} + mod for_loops { fn range1() -> usize { let mut acc = 0; diff --git a/tests/naming/Cargo.toml b/tests/naming/Cargo.toml index 557fd24e6..12531b483 100644 --- a/tests/naming/Cargo.toml +++ b/tests/naming/Cargo.toml @@ -6,4 +6,4 @@ edition = "2021" [dependencies] [package.metadata.hax-tests] -into."fstar+coq" = { snapshot = "stdout" } +into."fstar" = { snapshot = "stdout" } diff --git a/tests/naming/src/lib.rs b/tests/naming/src/lib.rs index 2879be61b..aa7514760 100644 --- a/tests/naming/src/lib.rs +++ b/tests/naming/src/lib.rs @@ -155,3 +155,6 @@ mod ambiguous_names { debug(0, a) } } + +/// From issue https://github.com/hacspec/hax/issues/839 +fn string_shadows(string: &str, n: &str) {} diff --git a/tests/pattern-or/src/lib.rs b/tests/pattern-or/src/lib.rs index ebf5fca30..9fa331111 100644 --- a/tests/pattern-or/src/lib.rs +++ b/tests/pattern-or/src/lib.rs @@ -10,3 +10,31 @@ pub fn bar(x: E) { E::A | E::B => (), } } +pub fn nested(x: Option) -> i32 { + match x { + Some(1 | 2) => 1, + Some(x) => x, + None => 0, + } +} + +pub fn deep(x: (i32, Option)) -> i32 { + match x { + (1 | 2, Some(3 | 4)) => 0, + (x, _) => x, + } +} + +pub fn equivalent(x: (i32, Option)) -> i32 { + match x { + (1, Some(3)) | (1, Some(4)) | (2, Some(3)) | (2, Some(4)) => 0, + (x, _) => x, + } +} + +pub fn deep_capture(x: Result<(i32, i32), (i32, i32)>) -> i32 { + match x { + Ok((1 | 2, x)) | Err((3 | 4, x)) => x, + Ok((x, _)) | Err((x, _)) => x, + } +} diff --git a/tests/traits/src/lib.rs b/tests/traits/src/lib.rs index 9821c42d0..e8968be87 100644 --- a/tests/traits/src/lib.rs +++ b/tests/traits/src/lib.rs @@ -163,3 +163,116 @@ mod implicit_dependencies_issue_667 { } } } + +// Related to issue 719 +mod interlaced_consts_types { + struct Bar([FooType; FooConst]); + + trait Foo { + fn fun(x: [FooType; FooConst], y: [FunType; FunConst]); + } + + impl Foo for SelfType { + fn fun(x: [FooType; FooConst], y: [FunType; FunConst]) {} + } +} + +// Related to issue #719 (after reopen) +mod implicit_explicit_calling_conventions { + struct Type { + field: [TypeArg; ConstArg], + } + + trait Trait { + fn method( + self, + value_TypeArg: TypeArg, + value_Type: Type, + ); + fn associated_function( + _self: Self, + value_TypeArg: TypeArg, + value_Type: Type, + ); + } + + impl Trait for () { + fn method( + self, + value_TypeArg: TypeArg, + value_Type: Type, + ) { + } + fn associated_function( + _self: Self, + value_TypeArg: TypeArg, + value_Type: Type, + ) { + } + } + + trait SubTrait: Trait { + type AssocType: Trait; + } + + fn method_caller< + MethodTypeArg, + TypeArg, + const ConstArg: usize, + const MethodConstArg: usize, + ImplTrait: Trait, + >( + x: ImplTrait, + value_TypeArg: TypeArg, + value_Type: Type, + ) { + x.method::(value_TypeArg, value_Type); + } + + fn associated_function_caller< + MethodTypeArg, + TypeArg, + const ConstArg: usize, + const MethodConstArg: usize, + ImplTrait: Trait, + >( + x: ImplTrait, + value_TypeArg: TypeArg, + value_Type: Type, + ) { + ImplTrait::associated_function::( + x, + value_TypeArg, + value_Type, + ); + } +} + +mod type_alias_bounds_issue_707 { + struct StructWithGenericBounds(T); + type SynonymA = StructWithGenericBounds; + type SynonymB = StructWithGenericBounds<(T, T)>; +} + +// Related to PR 730 +mod block_size { + pub trait BlockSizeUser { + type BlockSize; + } + pub trait ParBlocksSizeUser: BlockSizeUser {} + + pub trait BlockBackend: ParBlocksSizeUser { + fn proc_block(block: Vec<::BlockSize>); + } +} + +// issue 692 +mod recursive_trait_with_assoc_type { + pub trait Trait1 { + type T: Trait1; + } + + pub trait Trait2: Trait1 { + type U; + } +}