diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
index 6b3dd2fa508..102ee1cc4bb 100644
--- a/.devcontainer/devcontainer.json
+++ b/.devcontainer/devcontainer.json
@@ -52,7 +52,6 @@
// See https://containers.dev/features for a list of all available features
"features": {
- "fish": "latest",
"java": "17",
"python": "latest"
},
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 5b6c64fc76d..86f5d42bfd6 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -110,7 +110,7 @@ jobs:
# Run a subset of the tests with the purification optimization enabled
# to ensure that we do not introduce regressions.
purification-tests:
- needs: [fmt-check, clippy-check, check-deps, smir-check, quick-tests]
+ #needs: [fmt-check, clippy-check, check-deps, smir-check, quick-tests]
runs-on: ubuntu-latest
env:
PRUSTI_ENABLE_PURIFICATION_OPTIMIZATION: true
@@ -162,6 +162,36 @@ jobs:
# python x.py test --all pass/pure-fn/ref-mut-arg.rs
# python x.py test --all pass/rosetta/Ackermann_function.rs
# python x.py test --all pass/rosetta/Heapsort.rs
+ - name: custom_heap_encoding
+ env:
+ PRUSTI_VIPER_BACKEND: carbon
+ PRUSTI_CUSTOM_HEAP_ENCODING: true
+ PRUSTI_TRACE_WITH_SYMBOLIC_EXECUTION: false
+ PRUSTI_PURIFY_WITH_SYMBOLIC_EXECUTION: false
+ run: |
+ python x.py test custom_heap_encoding
+ - name: purify_with_symbolic_execution
+ env:
+ PRUSTI_VIPER_BACKEND: carbon
+ PRUSTI_CUSTOM_HEAP_ENCODING: false
+ PRUSTI_PURIFY_WITH_SYMBOLIC_EXECUTION: true
+ run: |
+ python x.py test custom_heap_encoding
+ - name: custom_heap_encoding and purify_with_symbolic_execution
+ env:
+ PRUSTI_VIPER_BACKEND: carbon
+ PRUSTI_CUSTOM_HEAP_ENCODING: true
+ PRUSTI_PURIFY_WITH_SYMBOLIC_EXECUTION: true
+ run: |
+ python x.py test custom_heap_encoding
+ - name: trace_with_symbolic_execution
+ env:
+ PRUSTI_VIPER_BACKEND: silicon
+ PRUSTI_CUSTOM_HEAP_ENCODING: false
+ PRUSTI_TRACE_WITH_SYMBOLIC_EXECUTION: false
+ PRUSTI_PURIFY_WITH_SYMBOLIC_EXECUTION: false
+ run: |
+ python x.py test custom_heap_encoding
- name: Run with purification.
env:
PRUSTI_VIPER_BACKEND: silicon
diff --git a/Cargo.lock b/Cargo.lock
index f96d098ad6e..9eebb683d4b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -43,7 +43,7 @@ version = "0.1.0"
dependencies = [
"compiletest_rs",
"derive_more",
- "env_logger",
+ "env_logger 0.10.0",
"glob",
"log",
"prusti-rustc-interface",
@@ -914,18 +914,51 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0688c2a7f92e427f44895cd63841bff7b29f8d7a1648b9e7e07a4a365b2e1257"
+[[package]]
+name = "dogged"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2638df109789fe360f0d9998c5438dd19a36678aaf845e46f285b688b1a1657a"
+
[[package]]
name = "dunce"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bd4b30a6560bbd9b4620f4de34c3f14f60848e58a9b7216801afcb4c7b31c3c"
+[[package]]
+name = "egg"
+version = "0.9.3"
+source = "git+https://github.com/vakaras/egg.git?branch=from_enodes_with_explanations#3d24f905a2724dde6ac2ddcf438ad9bd638b5bda"
+dependencies = [
+ "env_logger 0.9.3",
+ "fxhash",
+ "hashbrown",
+ "indexmap",
+ "instant",
+ "log",
+ "smallvec",
+ "symbol_table",
+ "symbolic_expressions",
+ "thiserror",
+]
+
[[package]]
name = "either"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
+[[package]]
+name = "ena"
+version = "0.14.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1"
+dependencies = [
+ "dogged",
+ "log",
+]
+
[[package]]
name = "encoding_rs"
version = "0.8.32"
@@ -935,6 +968,15 @@ dependencies = [
"cfg-if",
]
+[[package]]
+name = "env_logger"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7"
+dependencies = [
+ "log",
+]
+
[[package]]
name = "env_logger"
version = "0.10.0"
@@ -1183,6 +1225,15 @@ dependencies = [
"slab",
]
+[[package]]
+name = "fxhash"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
+dependencies = [
+ "byteorder",
+]
+
[[package]]
name = "generic-array"
version = "0.14.7"
@@ -2121,7 +2172,7 @@ name = "prusti"
version = "0.2.2"
dependencies = [
"chrono",
- "env_logger",
+ "env_logger 0.10.0",
"lazy_static",
"log",
"prusti-common",
@@ -2198,7 +2249,7 @@ version = "0.1.0"
dependencies = [
"bincode",
"clap",
- "env_logger",
+ "env_logger 0.10.0",
"lazy_static",
"log",
"num_cpus",
@@ -2241,7 +2292,7 @@ version = "0.2.0"
dependencies = [
"cargo-test-support",
"compiletest_rs",
- "env_logger",
+ "env_logger 0.10.0",
"log",
"prusti",
"prusti-launch",
@@ -2271,9 +2322,12 @@ dependencies = [
name = "prusti-viper"
version = "0.1.0"
dependencies = [
+ "analysis",
"backtrace",
"derive_more",
"diffy",
+ "egg",
+ "ena",
"itertools",
"lazy_static",
"log",
@@ -2284,6 +2338,7 @@ dependencies = [
"prusti-rustc-interface",
"prusti-server",
"regex",
+ "rsmt2",
"rustc-hash",
"serde",
"serde_json",
@@ -2495,6 +2550,15 @@ dependencies = [
"serde",
]
+[[package]]
+name = "rsmt2"
+version = "0.16.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2efb7d3e5fdbdc6a38a6026853350e3fa03f8ff791affe6f5aa5f2d590216f9e"
+dependencies = [
+ "error-chain",
+]
+
[[package]]
name = "rust-ini"
version = "0.18.0"
@@ -2882,6 +2946,22 @@ version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
+[[package]]
+name = "symbol_table"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32bf088d1d7df2b2b6711b06da3471bc86677383c57b27251e18c56df8deac14"
+dependencies = [
+ "ahash",
+ "hashbrown",
+]
+
+[[package]]
+name = "symbolic_expressions"
+version = "5.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7c68d531d83ec6c531150584c42a4290911964d5f0d79132b193b67252a23b71"
+
[[package]]
name = "syn"
version = "1.0.109"
@@ -2920,7 +3000,7 @@ dependencies = [
name = "systest"
version = "0.1.0"
dependencies = [
- "env_logger",
+ "env_logger 0.10.0",
"error-chain",
"jni",
"jni-gen",
@@ -2980,7 +3060,7 @@ dependencies = [
"clap",
"color-backtrace",
"csv",
- "env_logger",
+ "env_logger 0.10.0",
"failure",
"glob",
"log",
@@ -3431,7 +3511,7 @@ version = "0.1.0"
dependencies = [
"bencher",
"bincode",
- "env_logger",
+ "env_logger 0.10.0",
"error-chain",
"futures",
"jni",
@@ -3450,7 +3530,7 @@ dependencies = [
name = "viper-sys"
version = "0.1.0"
dependencies = [
- "env_logger",
+ "env_logger 0.10.0",
"error-chain",
"jni",
"jni-gen",
diff --git a/benchmark_silicon/.gitignore b/benchmark_silicon/.gitignore
new file mode 100644
index 00000000000..2d98968b221
--- /dev/null
+++ b/benchmark_silicon/.gitignore
@@ -0,0 +1,2 @@
+env
+*.swp
diff --git a/benchmark_silicon/AnalyzeReport.ipynb b/benchmark_silicon/AnalyzeReport.ipynb
new file mode 100644
index 00000000000..0a85863a412
--- /dev/null
+++ b/benchmark_silicon/AnalyzeReport.ipynb
@@ -0,0 +1,318 @@
+{
+ "cells": [
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Analyze results of `bechmark_silicon.py`"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import pandas as pd\n",
+ "# Load the results from the JSON file\n",
+ "report = pd.read_json('report.json')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " algorithms | \n",
+ " identifier | \n",
+ " file_path | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 6 | \n",
+ " [] | \n",
+ " 1119 | \n",
+ " ../viperserver/silicon/silver/src/test/resources/transformations/Macros/Hygienic/nestedRef.vpr | \n",
+ "
\n",
+ " \n",
+ " 8 | \n",
+ " [] | \n",
+ " 1130 | \n",
+ " ../viperserver/silicon/silver/src/test/resources/transformations/Macros/Expansion/simple2Ref.vpr | \n",
+ "
\n",
+ " \n",
+ " 9 | \n",
+ " [] | \n",
+ " 731 | \n",
+ " ../viperserver/silicon/silver/src/test/resources/all/issues/silicon/0203.vpr | \n",
+ "
\n",
+ " \n",
+ " 11 | \n",
+ " [] | \n",
+ " 1141 | \n",
+ " ../viperserver/silicon/silver/src/test/resources/transformations/FoldConstants/simple.vpr | \n",
+ "
\n",
+ " \n",
+ " 12 | \n",
+ " [] | \n",
+ " 1249 | \n",
+ " ../viperserver/silicon/silver/src/test/resources/termination/methods/loops/loopCondition.vpr | \n",
+ "
\n",
+ " \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ "
\n",
+ " \n",
+ " 1067 | \n",
+ " [] | \n",
+ " 769 | \n",
+ " ../viperserver/silicon/silver/src/test/resources/all/issues/silicon/0328b.vpr | \n",
+ "
\n",
+ " \n",
+ " 1068 | \n",
+ " [] | \n",
+ " 808 | \n",
+ " ../viperserver/silicon/silver/src/test/resources/all/issues/silicon/0045.vpr | \n",
+ "
\n",
+ " \n",
+ " 1069 | \n",
+ " [] | \n",
+ " 678 | \n",
+ " ../viperserver/silicon/silver/src/test/resources/all/issues/silver/0168_lib.vpr | \n",
+ "
\n",
+ " \n",
+ " 1073 | \n",
+ " [] | \n",
+ " 491 | \n",
+ " ../viperserver/silicon/silver/src/test/resources/all/sets/sets.vpr | \n",
+ "
\n",
+ " \n",
+ " 1079 | \n",
+ " [] | \n",
+ " 1077 | \n",
+ " ../viperserver/silicon/silver/src/test/resources/transformations/CopyPropagation/simple.vpr | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
289 rows × 3 columns
\n",
+ "
"
+ ],
+ "text/plain": [
+ " algorithms identifier \n",
+ "6 [] 1119 \\\n",
+ "8 [] 1130 \n",
+ "9 [] 731 \n",
+ "11 [] 1141 \n",
+ "12 [] 1249 \n",
+ "... ... ... \n",
+ "1067 [] 769 \n",
+ "1068 [] 808 \n",
+ "1069 [] 678 \n",
+ "1073 [] 491 \n",
+ "1079 [] 1077 \n",
+ "\n",
+ " file_path \n",
+ "6 ../viperserver/silicon/silver/src/test/resources/transformations/Macros/Hygienic/nestedRef.vpr \n",
+ "8 ../viperserver/silicon/silver/src/test/resources/transformations/Macros/Expansion/simple2Ref.vpr \n",
+ "9 ../viperserver/silicon/silver/src/test/resources/all/issues/silicon/0203.vpr \n",
+ "11 ../viperserver/silicon/silver/src/test/resources/transformations/FoldConstants/simple.vpr \n",
+ "12 ../viperserver/silicon/silver/src/test/resources/termination/methods/loops/loopCondition.vpr \n",
+ "... ... \n",
+ "1067 ../viperserver/silicon/silver/src/test/resources/all/issues/silicon/0328b.vpr \n",
+ "1068 ../viperserver/silicon/silver/src/test/resources/all/issues/silicon/0045.vpr \n",
+ "1069 ../viperserver/silicon/silver/src/test/resources/all/issues/silver/0168_lib.vpr \n",
+ "1073 ../viperserver/silicon/silver/src/test/resources/all/sets/sets.vpr \n",
+ "1079 ../viperserver/silicon/silver/src/test/resources/transformations/CopyPropagation/simple.vpr \n",
+ "\n",
+ "[289 rows x 3 columns]"
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# Count how many empty lists are in `algorithms` column\n",
+ "report['algorithms'].apply(lambda x: len(x)).value_counts()\n",
+ "# report[['algorithms', 'identifier']]\n",
+ "# Show the rows where `algorithms` is empty\n",
+ "pd.set_option('display.max_colwidth', None)\n",
+ "report[report['algorithms'].apply(lambda x: len(x) == 0)][['algorithms', 'identifier', 'file_path']]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Iterate over algorithms and event kinds\n",
+ "all_event_kinds = set()\n",
+ "decide_and_or_per_algorithm = []\n",
+ "for row in report.itertuples():\n",
+ " algorithms_used = set()\n",
+ " for (resource, algorithm) in row.algorithms:\n",
+ " algorithms_used.add(algorithm)\n",
+ " for event_kinds in row.event_kinds:\n",
+ " event_kinds = dict(event_kinds)\n",
+ " all_event_kinds.update(event_kinds.keys())\n",
+ " decide_and_or_per_algorithm.append((str(list(sorted(algorithms_used))), event_kinds.get('DecideAndOr', 0)))\n",
+ "# decide_and_or_per_algorithm as DataFrame\n",
+ "decide_and_or_per_algorithm = pd.DataFrame(decide_and_or_per_algorithm, columns=['algorithms', 'DecideAndOr'])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "(0.0, 200.0)"
+ ]
+ },
+ "execution_count": 9,
+ "metadata": {},
+ "output_type": "execute_result"
+ },
+ {
+ "data": {
+ "image/png": "iVBORw0KGgoAAAANSUhEUgAABngAAAN9CAYAAACw9He/AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAACcG0lEQVR4nOz9e5xWZb0//r9mBhxAAUVFYKcySmnFpGa78QRIOiKGisPU9lRqbrPysFOsNnw6qPWBDsq2zI671DxQX2kcjbLERBi30k7bmlS2xcAO4gFNkIM0zNy/P/rM/JxmQEeBYTHP5+Mxj+G+rmut9b5P3PfixbWuslKpVAoAAAAAAACFUd7TBQAAAAAAANA9Ah4AAAAAAICCEfAAAAAAAAAUjIAHAAAAAACgYAQ8AAAAAAAABSPgAQAAAAAAKBgBDwAAAAAAQMEIeAAAAAAAAApGwAMAAAAAAFAwAh4AANjOlJWV5dJLL+3pMrZ799xzT8rKynLPPfdsctyll16asrKyrFixYusU9grOPPPMjBw5sseO3/Z4dGfstvLYAQDAtkTAAwAAr9J1112XsrKyDj9Dhw7N+PHjc8cdd/R0ea/bb3/721x66aVZtmxZT5dCLzNjxow0Njb2dBkAAFAoAh4AAOimyy+/PDfccEO+973v5eMf/3ieffbZHHfccZk7d25Pl/a6/Pa3v81ll10m4GGL+uQnP5l169Z1aBPwAABA9/Xp6QIAAKBoJk6cmHe84x3tt88+++zssccemT17diZNmtSDlRXHhg0b0tramh122KGnS2ErWbNmTXbcccf06dMnffo4FQUAgNfLDB4AAHiddt555/Tv37/TP1qvWbMmU6dOzZ577pnKysrst99+ueKKK1IqlZIk69aty/7775/999+/w4yG559/PsOHD89hhx2WlpaWJH9fN2WnnXbKH/7wh0yYMCE77rhjRowYkcsvv7x9f5vyP//zP5k4cWIGDRqUnXbaKUcddVQWLVrU3n/dddflPe95T5Jk/Pjx7Zege6X1ZW655Za85S1vSb9+/TJ69OjceuutndZ4WbZsWcrKynLFFVfkqquuyr777pvKysr89re/TZLcfffdGTNmTHbcccfsvPPOOfHEE/O73/2uw3E2tm5MV+u5lJWV5fzzz89NN92U/fbbL/369cvBBx+chQsXdtr+L3/5Sz7wgQ9kjz32SGVlZd761rfmu9/9bqdxf/7znzN58uTsuOOOGTp0aC666KKsX79+k4/NP1qxYkXe+973ZtCgQdl1113zb//2b3nppZfa+8eNG5cDDjigy23322+/TJgwYZP7v+222/Lud787I0aMSGVlZfbdd9989rOfbX8Nbcpzzz2X973vfRk0aFB23nnnnHHGGXn44YdTVlaW6667rsPYV/N8tT0vv/3tb3Pqqadml112yRFHHNGhr01ZWVnWrFmT66+/vv11d+aZZ3bY3wsvvJAzzzwzO++8cwYPHpyzzjora9eu7TCm7Xlve032798/hx56aB555JEkyTe/+c2MGjUq/fr1y5FHHtlpptpjjz2WKVOmZNiwYenXr1/e8IY35OSTT87KlStf8fEDAICe4L9NAQBAN61cuTIrVqxIqVTKM888k6uvvjqrV6/O6aef3j6mVCrlhBNOyPz583P22WfnwAMPzM9+9rN87GMfy1/+8pf8x3/8R/r375/rr78+hx9+eP7P//k/mTVrVpLkvPPOy8qVK3PdddeloqKifZ8tLS059thjc8ghh+SLX/xifvrTn+Yzn/lMNmzYkMsvv3yj9f7mN7/JmDFjMmjQoHz84x9P3759881vfjNHHnlkFixYkJqamowdOzYXXnhhvvKVr2T69Ol585vfnCTtv7vy4x//OP/yL/+S6urqzJw5M3/9619z9tln55/+6Z+6HH/ttdfmpZdeygc/+MFUVlZmyJAhueuuuzJx4sTss88+ufTSS7Nu3bpcffXVOfzww/OrX/2qy1Dn1ViwYEF+8IMf5MILL0xlZWW+9rWv5dhjj81///d/Z/To0UmSp59+Ooccckh7MLD77rvnjjvuyNlnn51Vq1blox/9aJK/B3FHHXVU/vjHP+bCCy/MiBEjcsMNN+Tuu+/uVk3vfe97M3LkyMycOTOLFi3KV77ylfz1r3/N9773vSTJ+973vpxzzjlZvHhxe41J8stf/jL/+7//m09+8pOb3P91112XnXbaKRdffHF22mmn3H333fn0pz+dVatW5Utf+tJGt2ttbc3xxx+f//7v/86HP/zh7L///rnttttyxhlndBrb3efrPe95T974xjdmxowZGw0ib7jhhvzrv/5r3vnOd+aDH/xgkmTfffft9NhVVVVl5syZ+dWvfpX//M//zNChQ/OFL3yhw7impqbcfvvtOe+885IkM2fOzKRJk/Lxj388X/va1/KRj3wkf/3rX/PFL34xH/jAB9qfw7/97W+ZMGFC1q9fnwsuuCDDhg3LX/7yl8ydOzcvvPBCBg8evMnHHgAAekQJAAB4Va699tpSkk4/lZWVpeuuu67D2MbGxlKS0uc+97kO7fX19aWysrLSkiVL2tumTZtWKi8vLy1cuLB0yy23lJKUrrrqqg7bnXHGGaUkpQsuuKC9rbW1tfTud7+7tMMOO5SeffbZ9vYkpc985jPttydPnlzaYYcdSo8//nh725NPPlkaOHBgaezYse1tbceeP3/+q3o8qqurS294wxtKL774YnvbPffcU0pS2nvvvdvbli5dWkpSGjRoUOmZZ57psI8DDzywNHTo0NJzzz3X3vbwww+XysvLS+9///s73P+X77PNZz7zmdI/nta0PS8PPPBAe9sTTzxR6tevX+mkk05qbzv77LNLw4cPL61YsaLD9ieffHJp8ODBpbVr15ZKpVLpqquuKiUp/X//3//XPmbNmjWlUaNGvarHq63GE044oUP7Rz7ykVKS0sMPP1wqlUqlF154odSvX7/SJz7xiQ7jLrzwwtKOO+5YWr169SaP01bvy5177rmlAQMGlF566aX2tn98LH/4wx92es21tLSU3vWud5WSlK699tr29lf7fLXd51NOOWWjj8fL7bjjjqUzzjhjo2M/8IEPdGg/6aSTSrvuumuHtrb34tKlS9vbvvnNb5aSlIYNG1ZatWpVe/u0adNKSdrH/s///E8pSemWW27pVAMAAGyrXKINAAC66Zprrsm8efMyb9683HjjjRk/fnz+9V//NQ0NDe1jfvKTn6SioiIXXnhhh22nTp2aUqmUO+64o73t0ksvzVvf+tacccYZ+chHPpJx48Z12q7N+eef3/7ntpknf/vb33LXXXd1Ob6lpSV33nlnJk+enH322ae9ffjw4Tn11FNz7733ZtWqVd1+DJ588sk88sgjef/735+ddtqpvX3cuHGprq7ucpspU6Zk9913b7+9fPnyPPTQQznzzDMzZMiQ9va3ve1tqa2tzU9+8pNu19Xm0EMPzcEHH9x+e6+99sqJJ56Yn/3sZ2lpaUmpVMoPf/jDHH/88SmVSlmxYkX7z4QJE7Jy5cr86le/SvL353L48OGpr69v39+AAQPaZ5u8Wm2zStpccMEF7ftPksGDB+fEE0/M7Nmz22e7tLS05Ac/+EH75eE2pX///u1/fvHFF7NixYqMGTMma9euzaOPPrrR7X7605+mb9++Oeecc9rbysvLO9X7Wp6vD33oQ5us+dX6x/2MGTMmzz33XKfX7lFHHdVhFlFNTU2Sv7/2Bg4c2Kn9D3/4Q5K0z9D52c9+1unSbwAAsK0S8AAAQDe9853vzNFHH52jjz46p512Wn784x/nLW95S3vYkiRPPPFERowY0eEflZP//yXPnnjiifa2HXbYId/97nezdOnSvPjii7n22ms7rSuT/P0f3V8e0iTJm970piTptJ5Im2effTZr167Nfvvt16nvzW9+c1pbW/OnP/3p1d/5/6et/lGjRnXq66otSaqqqrrcx8ZqW7FiRdasWdPt2pLkjW98Y6e2N73pTVm7dm2effbZPPvss3nhhRfyrW99K7vvvnuHn7POOitJ8swzz7TXOWrUqE7PSVd1d6emfffdN+Xl5R2eu/e///354x//mKampiR/vyTa008/nfe9732vuP/f/OY3OemkkzJ48OAMGjQou+++e/tlAze1jswTTzyR4cOHZ8CAAR3a//F5fC3P1z8+56/VXnvt1eH2LrvskiT561//uslxbcHNnnvu2WV72/ZVVVW5+OKL85//+Z/ZbbfdMmHChFxzzTXW3wEAYJsm4AEAgNepvLw848ePz/Lly/PYY4+9pn387Gc/S5K89NJLr3kf27qXzzDprq4Cr+TvM1xei9bW1iTJ6aef3j4b6x9/Dj/88Ndc76vR1X2aMGFC9thjj9x4441JkhtvvDHDhg3L0Ucfvcl9vfDCCxk3blwefvjhXH755fnRj36UefPmta9R03Z/t7bX85y/3MvXonq50j+s67Oxca9m+yuvvDK//vWvM3369Kxbty4XXnhh3vrWt+bPf/7za6waAAC2rD49XQAAAGwPNmzYkCRZvXp1kmTvvffOXXfdlRdffLHDLJ62S2Xtvffe7W2//vWvc/nll+ess87KQw89lH/913/NI4880mlh99bW1vzhD39on7WTJP/7v/+bJJ0Wt2+z++67Z8CAAfn973/fqe/RRx9NeXl5++yGjYUoXWmrf8mSJZ36umrb1D42Vttuu+3WflmyXXbZJS+88EKncS+fCfVyXYVk//u//5sBAwa0XyZu4MCBaWlpecXwZO+9987ixYtTKpU6PEZd1b0pjz32WIcZLUuWLElra2uH566ioiKnnnpqrrvuunzhC19IY2NjzjnnnI0GFG3uueeePPfcc2loaMjYsWPb25cuXfqKde29996ZP39+1q5d22EWzz8+j915vrqrO6+9Lam6ujrV1dX55Cc/mfvuuy+HH354vvGNb+Rzn/tcT5cGAACdmMEDAACvU3Nzc+68887ssMMO7ZdgO+6449LS0pKvfvWrHcb+x3/8R8rKyjJx4sT2bc8888yMGDEiX/7yl3Pdddfl6aefzkUXXdTlsV6+v1KplK9+9avp27dvjjrqqC7HV1RU5Jhjjsltt93W4VJgTz/9dG6++eYcccQRGTRoUJK0/+N8V0HKPxoxYkRGjx6d733ve+2hVpIsWLAgjzzyyCtun/x9HaADDzww119/fYdjLl68OHfeeWeOO+649rZ99903K1euzK9//ev2tuXLl+fWW2/tct/3339/+xo6SfKnP/0pt912W4455phUVFSkoqIiU6ZMyQ9/+MMsXry40/bPPvts+5+PO+64PPnkk5kzZ05729q1a/Otb33rVd3PNtdcc02H21dffXWStL8W2rzvfe/LX//615x77rlZvXp1+2XWNqUtAHr5jJS//e1v+drXvvaK206YMCHNzc359re/3d7W2traqd7uPF/dteOOO76q192WsmrVqvaQtk11dXXKy8uzfv36HqoKAAA2zQweAADopjvuuKN9Js4zzzyTm2++OY899lj+/d//vT0sOf744zN+/Pj8n//zf7Js2bIccMABufPOO3Pbbbflox/9aPbdd98kyec+97k89NBD+fnPf56BAwfmbW97Wz796U/nk5/8ZOrr6zv8o3m/fv3y05/+NGeccUZqampyxx135Mc//nGmT5/ePiulK5/73Ocyb968HHHEEfnIRz6SPn365Jvf/GbWr1+fL37xi+3jDjzwwFRUVOQLX/hCVq5cmcrKyrzrXe/K0KFDu9zvjBkzcuKJJ+bwww/PWWedlb/+9a/56le/mtGjR3cIfTblS1/6UiZOnJhDDz00Z599dtatW5err746gwcPzqWXXto+7uSTT84nPvGJnHTSSbnwwguzdu3afP3rX8+b3vSmDkFOm9GjR2fChAm58MILU1lZ2R50XHbZZe1jPv/5z2f+/PmpqanJOeeck7e85S15/vnn86tf/Sp33XVXnn/++STJOeeck69+9at5//vfnwcffDDDhw/PDTfc0GnNmleydOnSnHDCCTn22GNz//3358Ybb8ypp56aAw44oMO4gw46KKNHj84tt9ySN7/5zXn729/+ivs+7LDDsssuu+SMM87IhRdemLKystxwww2dLmHWlcmTJ+ed73xnpk6dmiVLlmT//ffP7bff3n7/Xz675tU+X9118MEH56677sqsWbMyYsSIVFVVpaam5jXvr7vuvvvunH/++XnPe96TN73pTdmwYUNuuOGG9iAQAAC2SSUAAOBVufbaa0tJOvz069evdOCBB5a+/vWvl1pbWzuMf/HFF0sXXXRRacSIEaW+ffuW3vjGN5a+9KUvtY978MEHS3369CldcMEFHbbbsGFD6Z//+Z9LI0aMKP31r38tlUql0hlnnFHacccdS48//njpmGOOKQ0YMKC0xx57lD7zmc+UWlpaOmyfpPSZz3ymQ9uvfvWr0oQJE0o77bRTacCAAaXx48eX7rvvvk738dvf/nZpn332KVVUVJSSlObPn7/Jx+T73/9+af/99y9VVlaWRo8eXbr99ttLU6ZMKe2///7tY5YuXVpKUvrSl77U5T7uuuuu0uGHH17q379/adCgQaXjjz++9Nvf/rbTuDvvvLM0evTo0g477FDab7/9SjfeeGPpM5/5TOkfT2uSlM4777zSjTfeWHrjG99YqqysLB100EFd3penn366dN5555X23HPPUt++fUvDhg0rHXXUUaVvfetbHcY98cQTpRNOOKE0YMCA0m677Vb6t3/7t9JPf/rTV/UYtdX429/+tlRfX18aOHBgaZdddimdf/75pXXr1nW5zRe/+MVSktKMGTM2ue+X+6//+q/SIYccUurfv39pxIgRpY9//OOln/3sZ51qPOOMM0p77713h22fffbZ0qmnnloaOHBgafDgwaUzzzyz9F//9V+lJKXvf//7Hca+muer7T4/++yzG308Xu7RRx8tjR07ttS/f/9SktIZZ5yxyf20vReXLl3a3tb2vL/cxl578+fPLyUp3XLLLaVSqVT6wx/+UPrABz5Q2nfffUv9+vUrDRkypDR+/PjSXXfd1al+AADYVpSVSq/iv3QBAAA96swzz8ycOXNe9cyYnnTggQdm9913z7x583rk+GVlZTnvvPM6XR6vSL785S/noosuyrJly7LXXnv1SA2NjY056aSTcu+99+bwww/vkRoAAICNswYPAADwmjQ3N3dat+See+7Jww8/nCOPPLJnitoOlEqlfOc738m4ceO2Wrizbt26DrdbWlpy9dVXZ9CgQa/qEnEAAMDWZw0eAADgNfnLX/6So48+OqeffnpGjBiRRx99NN/4xjcybNiwfOhDH+rp8gpnzZo1uf322zN//vw88sgjue2227basS+44IKsW7cuhx56aNavX5+Ghobcd999mTFjRvr377/V6gAAAF49AQ8AAPCa7LLLLjn44IPzn//5n3n22Wez44475t3vfnc+//nPZ9ddd+3p8grn2Wefzamnnpqdd94506dPzwknnLDVjv2ud70rV155ZebOnZuXXnopo0aNytVXX53zzz9/q9UAAAB0jzV4AAAAAAAACsYaPAAAAAAAAAUj4AEAAAAAACgYAQ8AAAAAAEDBCHgAAAAAAAAKRsADAAAAAABQMAIeAAAAAACAghHwAAAAAAAAFIyABwAAAAAAoGAEPAAAAAAAAAUj4AEAAAAAACgYAQ8AAAAAAEDBCHgAAAAAAAAKRsADAAAAAABQMAIeAAAAAACAghHwAAAAAAAAFIyABwAAAAAAoGAEPAAAAAAAAAUj4AEAAAAAACgYAQ8AAAAAAEDBCHgAAAAAAAAKRsADAAAAAABQMAIeAAAAAACAghHwAAAAAAAAFIyABwAAAAAAoGAEPAAAAAAAAAUj4AEAAAAAACgYAQ8AAAAAAEDBCHgAAAAAAAAKRsADAAAAAABQMAIeAAAAAACAghHwAAAAAAAAFIyABwAAAAAAoGAEPAAAAAAAAAUj4AEAAAAAACgYAQ8AAAAAAEDBCHgAAAAAAAAKRsADAAAAAABQMAIeAAAAAACAghHwAAAAAAAAFIyABwAA2G4sW7YsZWVlue66615x7JlnnpmRI0du8Zo2h7Kyslx66aU9XQYAALANEfAAAACb1XXXXZeysrL2n379+mXEiBGZMGFCvvKVr+TFF1/s6RI3q3e+850pKyvL17/+9a1+7N/85jc5/fTT80//9E+prKzMiBEjctppp+U3v/nNVq8FAADYuvr0dAEAAMD26fLLL09VVVWam5vz1FNP5Z577slHP/rRzJo1K7fffnve9ra3bfZj7r333lm3bl369u272ffdlcceeyy//OUvM3LkyNx000358Ic/vFWOmyQNDQ055ZRTMmTIkJx99tmpqqrKsmXL8p3vfCdz5szJ97///Zx00klbrR4AAGDrEvAAAABbxMSJE/OOd7yj/fa0adNy9913Z9KkSTnhhBPyu9/9Lv3799+sx2ybMbS13HjjjRk6dGiuvPLK1NfXZ9myZVvlsm+PP/543ve+92WfffbJwoULs/vuu7f3/du//VvGjBmT973vffn1r3+dffbZZ6P7WbNmTXbcccctXi8AALD5uUQbAACw1bzrXe/Kpz71qTzxxBO58cYb29sfffTR1NfXZ8iQIenXr1/e8Y535Pbbb++0/QsvvJCLLrooI0eOTGVlZd7whjfk/e9/f1asWJFk42vwNDY2ZvTo0enXr19Gjx6dW2+9tcv6Wltbc9VVV+Wtb31r+vXrlz322CPnnntu/vrXv3Y5/uabb059fX0mTZqUwYMH5+abb+405tJLL01ZWVmWLFmSM888MzvvvHMGDx6cs846K2vXru0wdv369bnooouy++67Z+DAgTnhhBPy5z//udM+v/SlL2Xt2rX51re+1SHcSZLddtst3/zmN7NmzZp88Ytf7FTHb3/725x66qnZZZddcsQRR3R5vwAAgG2fgAcAANiq3ve+9yVJ7rzzziR/X0fmkEMOye9+97v8+7//e6688srsuOOOmTx5cocgZvXq1RkzZkyuvvrqHHPMMfnyl7+cD33oQ3n00Ue7DEHa3HnnnZkyZUrKysoyc+bMTJ48OWeddVYeeOCBTmPPPffcfOxjH8vhhx+eL3/5yznrrLNy0003ZcKECWlubu4w9he/+EWWLFmSU045JTvssEPq6upy0003bbSO9773vXnxxRczc+bMvPe97811112Xyy67rMOYf/3Xf81VV12VY445Jp///OfTt2/fvPvd7+60rx/96EcZOXJkxowZ0+Wxxo4dm5EjR+bHP/5xp773vOc9Wbt2bWbMmJFzzjlno/UCAADbNpdoAwAAtqo3vOENGTx4cB5//PEkf7+k2F577ZVf/vKXqaysTJJ85CMfyRFHHJFPfOIT7evIfOlLX8rixYvT0NDQYW2ZT37ykymVShs93ic+8YnsscceuffeezN48OAkybhx43LMMcdk7733bh9377335j//8z9z00035dRTT21vHz9+fI499tjccsstHdpvvPHG7Lnnnjn88MOTJCeffHK++93v5qGHHsqBBx7YqY6DDjoo3/nOd9pvP/fcc/nOd76TL3zhC0mShx9+ODfeeGM+8pGP5JprrkmSnHfeeTnttNPy61//un27lStX5sknn8yJJ564qYc5b3vb23L77bfnxRdfzMCBA9vbDzjggC5nGgEAAMViBg8AALDV7bTTTnnxxRfz/PPP5+67726f3bJixYqsWLEizz33XCZMmJDHHnssf/nLX5IkP/zhD3PAAQd0CHfalJWVdXmc5cuX56GHHsoZZ5zRHu4kSW1tbd7ylrd0GHvLLbdk8ODBqa2tba9jxYoVOfjgg7PTTjtl/vz57WM3bNiQH/zgB/mXf/mX9mO/613vytChQzc6i+dDH/pQh9tjxozJc889l1WrViVJfvKTnyRJLrzwwg7jPvrRj3a4/eKLLyZJh9CmK239bfvfWB0AAEAxCXgAAICtbvXq1Rk4cGCWLFmSUqmUT33qU9l99907/HzmM59JkjzzzDNJkscffzyjR4/u1nGeeOKJJMkb3/jGTn377bdfh9uPPfZYVq5cmaFDh3aqZfXq1e11JH+/7Nuzzz6bd77znVmyZEmWLFmSpUuXZvz48Zk9e3ZaW1s7HW+vvfbqcHuXXXZJkvb1fZ544omUl5dn33333WSdbcFNW9CzMRsLgqqqqja5HQAAUAwu0QYAAGxVf/7zn7Ny5cqMGjWqPQi55JJLMmHChC7Hjxo1aqvU1drauskZOLvvvnv7n9vGvPe97+1y7IIFCzJ+/PgObRUVFV2O3dTl5boyePDgDB8+vMNl27ry61//Ov/0T/+UQYMGdWjv379/t44HAABsmwQ8AADAVnXDDTckSSZMmJB99tknSdK3b98cffTRm9xu3333zeLFi7t1rLY1dh577LFOfb///e877f+uu+7K4YcfvskQZM2aNbntttvyL//yL6mvr+/Uf+GFF+amm27qFPC8mlpbW1vz+OOPd5i18491JsmkSZPy7W9/O/fee2+OOOKITv1NTU1ZtmxZzj333G7VAAAAFIdLtAEAAFvN3Xffnc9+9rOpqqrKaaedlqFDh+bII4/MN7/5zSxfvrzT+Geffbb9z1OmTMnDDz+cW2+9tdO4jc2CGT58eA488MBcf/31WblyZXv7vHnz8tvf/rbD2Pe+971paWnJZz/72U772bBhQ1544YUkya233po1a9bkvPPOS319faefSZMm5Yc//GHWr1//qh6TNhMnTkySfOUrX+nQftVVV3Ua+7GPfSz9+/fPueeem+eee65D3/PPP58PfehDGTBgQD72sY91qwYAAKA4zOABAAC2iDvuuCOPPvpoNmzYkKeffjp333135s2bl7333ju33357+vXrlyS55pprcsQRR6S6ujrnnHNO9tlnnzz99NO5//778+c//zkPP/xwkr+HGnPmzMl73vOefOADH8jBBx+c559/Prfffnu+8Y1v5IADDuiyjpkzZ+bd7353jjjiiHzgAx/I888/n6uvvjpvfetbs3r16vZx48aNy7nnnpuZM2fmoYceyjHHHJO+ffvmscceyy233JIvf/nLqa+vz0033ZRdd901hx12WJfHO+GEE/Ltb387P/7xj1NXV/eqH68DDzwwp5xySr72ta9l5cqVOeyww/Lzn/88S5Ys6TT2jW98Y66//vqcdtppqa6uztlnn52qqqosW7Ys3/nOd7JixYrMnj2703o+AADA9kPAAwAAbBGf/vSnkyQ77LBDhgwZkurq6lx11VU566yzMnDgwPZxb3nLW/LAAw/ksssuy3XXXZfnnnsuQ4cOzUEHHdS+jyTZaaed0tTUlM985jO59dZbc/3112fo0KE56qij8oY3vGGjdRx77LG55ZZb8slPfjLTpk3Lvvvum2uvvTa33XZb7rnnng5jv/GNb+Tggw/ON7/5zUyfPj19+vTJyJEjc/rpp+fwww/PM888k7vuuiunnHLKRtfUOeqoozJgwIDceOON3Qp4kuS73/1udt9999x0001pbGzMu971rvz4xz/Onnvu2Wnse97znuy///6ZOXNme6iz6667Zvz48Zk+fXpGjx7drWMDAADFUlbq7oqeAAAAAAAA9Chr8AAAAAAAABSMgAcAAAAAAKBgBDwAAAAAAAAF062AZ+bMmfnnf/7nDBw4MEOHDs3kyZPz+9//vsOYl156Keedd1523XXX7LTTTpkyZUqefvrpDmP++Mc/5t3vfncGDBiQoUOH5mMf+1g2bNjw+u8NAAAAAABAL9CtgGfBggU577zzsmjRosybNy/Nzc055phjsmbNmvYxF110UX70ox/llltuyYIFC/Lkk0+mrq6uvb+lpSXvfve787e//S333Xdfrr/++lx33XX59Kc/vfnuFQAAAAAAwHasrFQqlV7rxs8++2yGDh2aBQsWZOzYsVm5cmV233333Hzzzamvr0+SPProo3nzm9+c+++/P4ccckjuuOOOTJo0KU8++WT22GOPJMk3vvGNfOITn8izzz6bHXbYYfPcMwAAAAAAgO1Un9ez8cqVK5MkQ4YMSZI8+OCDaW5uztFHH90+Zv/9989ee+3VHvDcf//9qa6ubg93kmTChAn58Ic/nN/85jc56KCDOh1n/fr1Wb9+ffvt1tbWPP/889l1111TVlb2eu4CAAAAAADANqFUKuXFF1/MiBEjUl6+6YuwveaAp7W1NR/96Edz+OGHZ/To0UmSp556KjvssEN23nnnDmP32GOPPPXUU+1jXh7utPW39XVl5syZueyyy15rqQAAAAAAAIXxpz/9KW94wxs2OeY1BzznnXdeFi9enHvvvfe17uJVmzZtWi6++OL22ytXrsxee+2VpUuXZuDAgVv8+FAkj/zpr3n/9f+T751xUKr33KWnywGgAFpaWtLU1JT58+dn/PjxGTNmTCoqKnq6LAAKoLm5uf3zo2/fvj1dDgAF4fMDNu7FF19MVVXVq8o+XlPAc/7552fu3LlZuHBhhwRp2LBh+dvf/pYXXnihwyyep59+OsOGDWsf89///d8d9vf000+393WlsrIylZWVndqHDBmSQYMGvZa7ANutnVcn5ZUDsvMuu2TXXXft6XIAKIgTTjghffr0yXHHHecEC6CHrF27No8++mhPl9Etq9etz0OPL88/7bU0O/XvfN6+Ldt///0zYMCAni4DoFdqbm7OgAEDsuuuuzr/gH/Q9p54NcvTdCvgKZVKueCCC3LrrbfmnnvuSVVVVYf+gw8+OH379s3Pf/7zTJkyJUny+9//Pn/84x9z6KGHJkkOPfTQ/N//+3/zzDPPZOjQoUmSefPmZdCgQXnLW97SnXIAAABgu/Hoo4/m4IMP7ukyXpMv9nQBr8GDDz6Yt7/97T1dBgDAa9atgOe8887LzTffnNtuuy0DBw5sXzNn8ODB6d+/fwYPHpyzzz47F198cfvsmgsuuCCHHnpoDjnkkCTJMccck7e85S153/vely9+8Yt56qmn8slPfjLnnXdel7N0AAAAoDfYf//98+CDD/Z0Gd3y++Uv5OJbHsms91Rnv+E793Q53bL//vv3dAkAAK9LtwKer3/960mSI488skP7tddemzPPPDNJ8h//8R8pLy/PlClTsn79+kyY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AFtFRUVFxo0blzVr1mTcuHHCHXgdrMEDANCLNTQ0ZNSoUamtrc2sWbNSW1ubUaNGpaGhoadLAwAAADZBwAMA0Es1NDSkvr4+1dXVaWpqyuzZs9PU1JTq6urU19cLeQAAAGAbJuABAOiFWlpaMnXq1EyaNCmNjY2pqalJ//79U1NTk8bGxkyaNCmXXHJJWlpaerpUAAAAoAsCHgCAXqipqSnLli3L9OnTU17e8StheXl5pk2blqVLl6apqamHKgQAAAA2ZbMHPJdeemnKyso6/Oy///7t/S+99FLOO++87Lrrrtlpp50yZcqUPP3005u7DAAANmH58uVJktGjR3fZ39beNg4AAADYtmyRGTxvfetbs3z58vafe++9t73voosuyo9+9KPccsstWbBgQZ588snU1dVtiTIAANiI4cOHJ0kWL17cZX9be9s4AAAAYNvSZ4vstE+fDBs2rFP7ypUr853vfCc333xz3vWudyVJrr322rz5zW/OokWLcsghh2yJcgAA+AdjxozJyJEjM2PGjDQ2Nnboa21tzcyZM1NVVZUxY8b0TIEAAADAJm2RgOexxx7LiBEj0q9fvxx66KGZOXNm9tprrzz44INpbm7O0Ucf3T52//33z1577ZX7779/owHP+vXrs379+vbbq1atSpI0Nzenubl5S9wFtoANGza0//a8bTltj63HeMvyega2B1/4whdy8skn54QTTsjUqVOzbt263Hvvvbnyyivzk5/8JN///vfT2tqa1tbWni4VoNt8X9s6nH9sHV7PwPbG5wdsXHfeF5s94Kmpqcl1112X/fbbL8uXL89ll12WMWPGZPHixXnqqaeyww47ZOedd+6wzR577JGnnnpqo/ucOXNmLrvssk7td955ZwYMGLC57wJbyJ9WJ0mf3HvvvXlip56uZvs3b968ni5hu+b1DGwPKisr8/GPfzzXXntt++zq5O/fzT7+8Y+nsrIyP/nJT3qwQoDXzve1rcv5x5bl9Qxsr3x+QGdr16591WPLSqVSaQvWkhdeeCF77713Zs2alf79++ess87qMBsnSd75zndm/Pjx+cIXvtDlPrqawbPnnntmxYoVGTRo0JYsn83oN0+uyuSvL0rjhw/JW0d43raU5ubmzJs3L7W1tenbt29Pl7Pd8noGtictLS2555572j8/jjzyyFRUVPR0WQCvi+9rW4fz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KAAAoBOhwQMAAOCHPvzwQ0n/OYOnd+///4PPoqIiZWVledUlJiae73gAAAAAAOAMAowOAAAAgPOvsrKyXesAAAAAAMD5RYMHAADAD/3sZz+TJPXt21c1NTV68MEHNWLECD344IOqqalR3759veoAAAAAAEDnQoMHAADAD+3cuVOSNHDgQAUHB2vcuHEaPXq0xo0bp+DgYA0YMMCrDgAAAAAAdC6cwQMAAOCHysrKJEkff/yxevfurbq6OklSbm6uunXr5rnfXAcAAAAAADoXVvAAAAD4ocGDB59yzmQytaoOAAAAAAAYhwYPAACAH3rggQckSVarVdXV1SouLlZGRoaKi4v13XffyWq1etUBAAAAAIDOhS3aAAAA/NDWrVslSfX19YqMjFRcXJy+//577d+/X3feeafq6+s9dYmJiQYmBQAAANCV1NXVKSMjQ6WlpVq3bp1nm2gAZ48GDwAAgB+qrKyUJF155ZXavn27Vq1a5TXfPN5cBwAAAADnymazafXq1Z77O3bs0LJly5SWlqaCggLjggE+igYPAACAHwoPD5ckbd++Xf369VNCQoKqq6sVGhqqkpISbd++3asOAAAAAM5Fc3PHarXq0UcfVVRUlMrKyvTHP/5Rq1evls1mo8kDnCUaPAAAAH4oNjZW0n/O4Pnqq69kMplUVFSklJQUud1u9ezZU/X19Z46AAAAAGiruro6T3PnyJEjnvcf999/v5588kn17NlTq1evVl1dHdu1AWchwOgAAAAAOP9eeOEFSVJDQ4PS09NVWlqquro6lZaWKj09XQ0NDV51AAAAANBW06ZNkyRlZGRIkpYsWaIXX3xRS5YskSQ9+uijXnUAWocVPAAAAH5o3759kqSXXnpJ8+fPV3x8vGcuKipKL774oiZOnOipAwAAAIC22rNnjyTpu+++U/fu3dXY2ChJKioq0mOPPaa7777bqw5A67CCBwAAwA8NHjxYkuR2u7V3714VFxcrIyNDxcXF2rNnj5qamrzqAAAAAKCtLr30UknS8uXLFRoaqmXLlumVV17RsmXLFBoaqpdfftmrDkDr0OABAADwQ5MmTZLFYtGsWbPkdruVkJCg+Ph4JSQkyO1264knnpDFYtGkSZOMjgoAAADAxz311FOe2//+97919OhR/e///q+OHj2qf//73y3WATgztmjDeXPCdVwBwV+rrGa3AoJ7GB2ny2psbNQ3jd/os0OfyWLhn3hHKas5qoDgr3XCdVxSb6PjAMBZs1qtmjp1qhYtWqSIiAjNnj1bwcHBWr58uebOnauqqipNmzZNVqvV6KgAAAAAfNwrr7ziud23b1/P7aKiImVlZXnVNZ/HA+DM+Okvzptvavere9SzmvkPo5P4h6XrlhodocvrHiV9UztCVynM6CgA0CbZ2dmSpLy8PK+VOhaLRdOmTfPMAwAAAMC5aO3ZnpwBCpwdGjw4by7qPki1ZQ/rmTtGaHA/VvB0lMbGRm1+f7NG3TCKFTwdaN+Bo3rkrR26KGmQ0VEA4JxkZ2dr/vz5evbZZ7VhwwaNHj1aDz/8MCt3AAAAALSbQYP+8/OTnj176uuvv9b06dNVWlqq6667TtnZ2br44ot15MgRTx2A1uGnvzhvgszBajp+saJ6XabLQ9nSqqM0NDSozFKmoRcMVWBgoNFxuqym44fVdPyggszBRkcBAAAAAADwCSaTSVarVePGjVNISIjGjBnDL5cB54AGDwAAgB+bPn268vLy1NjYKOk/e2A/9thjmjp1Klu0AQAAAGgX+/fvlyTV1NQoJCRETU1NkqTc3FwFBAR47jfXAWgdGjwAAAB+avr06Vq0aJHCwsI0d+5cBQUF6cSJE5o9e7YWLVokSTR5AAAAAJyzwYMHe2673W6vuR/f/3EdgDMLMDoAAAAAzr/6+nrl5eUpLCxMFRUVuu+++9S3b1/dd999qqioUFhYmPLy8lRfX290VAAAAAA+7oEHHpAkWa1W1dTUKCcnRykpKcrJyVFNTY1nm7bmOgCtQ4MHAADADy1dulSNjY2aP3++mpqatGTJEr344otasmSJmpqaNG/ePDU2Nmrp0qVGRwUAAADg47Zu3SrpP79oFh0drYqKCkVERKiiokLR0dGeXyxrrgPQOmzRBgAA4If27dsnSdq+fbseeuihk87gmThxolcdAAAAALRVZWWlJOnWW2/VmjVr9Mc//tFrvnm8uQ5A69DgAQAA8EPNe1s///zzLZ7B8/zzz3vVAQAAAEBbhYeHS5LWrFmjW2+9VVFRUfr88881ZMgQlZWVac2aNV51AFqHBg8AAIAfmjBhgqZOnSqTyaTy8nKZzWYVFRUpJSVFd999t0JCQuR2uzVhwgSjowIAAADwcSNHjpTFYlFoaKgKCgrkdrs97z9MJpMiIiJUXV2tkSNHGh0V8Ck0eAAAAPzQ8uXLJUlut1sDBw5UY2Ojamtr1b17d1ksFrndbk/do48+amBSAAAAAL5uy5Ytamxs1IEDBzR27FglJydrz5492r9/v4qLi3XgwAG53W5t2bJFiYmJRscFfAYNHgAAAD/UfLZOYGCgDh486BlvPtw0MDBQDQ0NnMEDAAAA4Jw1n60zZcoUPffccyosLPTMWSwWTZkyRc888wxn8ABniQYPAACAH2o+W6ehoUGSFBYWposvvlhff/21qqqqPOOcwQMAAADgXDWfrfPMM88oNTVVN998s+cMnvXr1+uZZ57xqgPQOgFGBwAAAMD596tf/cpzu6KiQmPHjlVTU5PGjh2rioqKFusAAAAAoC2az+AJCwvTm2++qU8//VTvv/++Pv30U7355psKCwuTxWLhDB7gLLGCBwAAwA/dcMMNntsRERGe2zt27NCyZcu86srKys5rNgAAAABdS/MZPFVVVerVq5dn/KfvPziDBzg7rOABAADwQz8+d6c96gAAAADgVFp7tg5n8ABnhwYPAACAHwoNDfXcPnLkiHJycpSSkqKcnBwdOXKkxToAAAAAaIs+ffpIkgIDA3Xs2DEVFxcrIyNDxcXFOnbsmAIDA73qALQODR4AAAA/9ONtD/bt26dZs2apqKhIs2bN0r59+1qsAwAAAIC2+Otf/ypJGjhwoIKCgpSQkKD4+HglJCQoKChIAwcO9KoD0Do0eAAAAPzQt99+67k9YsQIHT9+XJJ0/PhxjRgxosU6AAAAAGiLL774QtJ/frnMZrOptLRUdXV1Ki0tlc1m8/ySWXMdgNahwQMAAOCHLr300natAwAAAIBTaX5fMXbsWO3cuVPx8fEaP3684uPjtWvXLtlsNq86AK1DgwcAAMAPTZo0yXN7+/btGjRokIKDgzVo0CBt3769xToAAAAAaItFixZJktasWaNPP/3U6wyeTz75REVFRV51AFrHYnQAAAAAnH9XXXWV5/bVV1+t4OBgNTQ06ODBg7r66qu96urq6oyICAAAAKCL6Natm9LS0rR69Wr17t1bAwcO1LFjx7R69Wp9+eWXamhoUFpamrp162Z0VMCn0OABAADwQydOnPDcbmpq0rFjxyTJ89+W6gAAAACgrQoKCtSnTx8dPnzYc+ZOs969e6ugoMCYYIAPY4s2AAAAPxQUFOR1v0ePHho4cKB69Ohx2joAAAAAaItrr71Whw8flslk0pAhQzx/TCaTDh8+rGuvvdboiIDPocEDAADghzZs2OC5vXv3bh06dEhLlizRoUOHtHv37hbrAAAAAKAtjh49qm3btslkMunYsWPatWuXsrOztWvXLh07dkwmk0nbtm3T0aNHjY4K+BQaPAAAAH5o7NixntuXXXaZQkND5XA4FBoaqssuu6zFOgAAAABoi7vuukuS9F//9V8KDg72mgsODtZvfvMbrzoArWNog+e5555TZGSkgoODFRsbq3/84x9GxgEAAPAbP/zwg9f9I0eO6H/+53905MiR09YBAAAAwNlqPnMnKyurxfmMjAyvOgCtY1iD56233lJGRoZmz56t7du3a/jw4brlllt04MABoyIBAAD4jT59+kiSoqKi9MUXX3h+iy44OFhffPGFBg0a5FUHAAAAAG01ePBgSVJOTk6L87m5uV51AFrHsAZPbm6uJk6cqHvvvVeXX365li1bppCQEP35z382KhIAAIDf2LFjhySprKxMffv2VU1NjQoKClRTU6O+fftq//79XnUAAAAA0FavvfaaJOn111/X8ePHveaOHz+uN99806sOQOtYjHjQ+vp6ffTRR5oxY4ZnLCAgQDfddJM++OCDk+pPnDihEydOeO4fPnxYknTo0CE1NDR0fGC0i28P/KCmE8f0wWf79cP3vYyO0yrHjx/T/jLfWhra1OjSJ598qgPH3AqwmI2Oc1YGRQ1WcHCI0TFa5YvvatV04ph++P57VQc3Gh0H6NIqa45o9ScfGx3jrNQerdEXn/7L6BhnFBLZXS5Xo/pf0V/duvfUxdGX657HJqiu9oiCBgTJbLbo0aWLjY55RpdcfoW69/CN1xaS1K9nkMb8fJi6WboZHQXo0nj/cX7w/uP84P0HcP7w/qPjhP1ygH747oD6DOmjiy8ZogvCBykj7w/6+ovPZY2wqs/P+mlC9lyjY54R7z/Q0Zq3Tne73WesNblbU9XOvvnmG1188cXasmWLrr/+es/49OnTVVJSoq1bt3rVz5kzR3Pndv5/3AAAAAAAAAAAAOfqq6++UkRExGlrDFnBc7ZmzJjhOWhLkpqamnTo0CGFhobKZDIZmAzofGpqajRgwAB99dVX6tXLd36bAABgLK4fAIC24PoBAGgLrh/Aqbndbh05ckQXXXTRGWsNafD87Gc/k9lsVlVVldd4VVWV+vfvf1J9UFCQgoKCvMY48Bc4vV69enGBBACcNa4fAIC24PoBAGgLrh9Ay3r37t2quoAOztEiq9Wqq666Su+++65nrKmpSe+++67Xlm0AAAAAAAAAAAA4mWFbtGVkZOjuu+/W1VdfrWuvvVZ//OMfVVtbq3vvvdeoSAAAAAAAAAAAAD7BsAbPHXfcoYMHD+qJJ57Qt99+qxEjRmjdunUKCwszKhLQJQQFBWn27NknbWsIAMDpcP0AALQF1w8AQFtw/QDah8ntdruNDgEAAAAAAAAAAIDWM+QMHgAAAAAAAAAAALQdDR4AAAAAAAAAAAAfQ4MHAAAAAAAAAADAx9DgAX4kMTFRJpNJJpNJO3bsMDpOq5lMJhUUFBgd45zdc889nue/K3w9AHC2fPE6dK7/z46MjPR8zT/88EO75QIAtI5R1x5e+wOA//npNae8vNxzf8SIEUbHA3wSDR7gJyZOnKjKykoNGzZMkjwXm64kMTFRK1asaHV9Rz0Hc+bM0T333OO5/8wzz6iysrLdHwcAfMmPr0P+cA3atm2bVq1aZVwgAMB5ufbw2h8AIHlfcwYMGKDKykplZmYaHQvwWRajAwCdTUhIiPr379+un7O+vl5Wq7VdP2dX1Lt3b/Xu3dvoGABgqPa+DnX2a9CFF16oCy64wOgYAODXOuI90Jnw2h8A/NNPrzn9+/dXjx49DEwE+DZW8ABt8NJLL2nAgAEKCQnR2LFjlZubqz59+njm58yZoxEjRmj58uWKiopScHCwJOmHH37QhAkTdOGFF6pXr14aPXq0Pv74Y6/PvXr1al155ZUKDg7WJZdcorlz56qxsdEzv2fPHsXHxys4OFiXX365iouLvT5+9OjRmjx5stfYwYMHZbVa9e6777bbc7BixQoNHDjQ8xwsXry4xefghRde8DxXt99+uw4fPtxuGQDAH3ENAgCcb7z2BwAA6Jxo8ABnafPmzXrwwQf1yCOPaMeOHUpOTtZTTz11Ut3evXu1atUqORwOz17Wv/rVr3TgwAGtXbtWH330ka688krdeOONOnTokCTJ6XTqt7/9rR555BF9+umneuGFF7RixQrP529qapLdbpfVatXWrVu1bNky/f73v/d63AkTJujNN9/UiRMnPGOvv/66Lr74Yo0ePbpdnoOtW7fq/vvv1+TJk7Vjxw4lJSVp/vz5LT4Hb7/9tv72t79p3bp1+uc//6lJkya1SwYA8EdcgwAA5xuv/QEAADoxNwCPhIQE9yOPPHLamjvuuMN96623eo3deeed7t69e3vuz5492x0YGOg+cOCAZ8zpdLp79erlPn78uNfHDh482P3CCy+43W63+8Ybb3QvWLDAa/61115zh4eHu91ut/vvf/+722KxuL/++mvP/Nq1a92S3O+8847b7Xa76+rq3H379nW/9dZbnporrrjCPWfOnNN/8Wdh/Pjx7pSUFK+xO+6446TnwGw2uysqKryyBgQEuCsrK0/7+X/89QCAPznTdairXoM2btzoluT+/vvvT1sHAGh/Z7r28NofANBeTnXNmT17tnv48OHnPQ/QFbCCBzhLu3fv1rXXXus19tP7kjRo0CBdeOGFnvsff/yxjh49qtDQUPXo0cPzp6ysTPv27fPUzJs3z2u++fC5Y8eO6bPPPtOAAQN00UUXeT7v9ddf7/W4wcHBuuuuu/TnP/9ZkrR9+3bt2rXL60DTc/XZZ58pNjbWa+ynOSRp4MCBuvjii71qmpqatHv37nbLAgD+hGsQAOB847U/AABA52UxOgDQVXXv3t3r/tGjRxUeHq733nvvpNrm/auPHj2quXPnym63n1TTfIZCa0yYMEEjRoxQRUWFXnnlFY0ePVqDBg06q/wAAN/FNQgAAAAAgK6PBg9wli677DJt27bNa+yn91ty5ZVX6ttvv5XFYlFkZOQpa3bv3q3o6OgW54cOHaqvvvpKlZWVCg8PlySVlpaeVBcTE6Orr75aL730kt5880396U9/OmO+szF06FBt3brVa6ylHF9++aW++eYbz297l5aWKiAgQJdddlm75gEAf8E1CABwvvHaHwAAoPOiwQOcpYcffljx8fHKzc3Vbbfdpg0bNmjt2rUymUyn/bibbrpJ119/vWw2m7KzszVkyBB98803WrNmjcaOHaurr75aTzzxhFJTUzVw4EClp6crICBAH3/8sXbt2qX58+frpptu0pAhQ3T33Xdr0aJFqqmp0eOPP97i402YMEGTJ09W9+7dNXbs2HZ9DqZMmaJRo0YpJydHaWlp+vvf/65169adVBccHKy7775bOTk5qqmp0ZQpU3T77berf//+7ZoHAPwF1yAAwPnGa38AAIDOizN4gLM0atQoLVu2TLm5uRo+fLjWrVunqVOnnnH7GpPJpKKiIsXHx+vee+/VkCFD9Otf/1r79+9XWFiYJOmWW25RYWGh1q9fr2uuuUbXXXed8vLyPFvbBAQE6J133lFdXZ2uvfZaTZgwQU899VSLjzd+/HhZLBaNHz/+jNnuueceJSYmtvo5uO666/TSSy/pmWee0fDhw7V+/XrNmjXrpLro6GjZ7XalpKTo5ptv1hVXXKGlS5e2+nEAAN664jUIANC58dofAACg82IFD9AGEydO1MSJE73u/3hLmzlz5mjOnDknfVzPnj21ZMkSLVmy5JSf+5ZbbtEtt9xyyvkhQ4bI6XR6jbnd7pPqvvvuOx0/flz333//6b4USVJZWZmSkpLOWPdj9913n+677z7P/RUrVrRY99BDD+mhhx46q88NADi1rnYNAgB0frz2BwAA6JxYwQP8xNKlS9WjRw/t3LnzlDU5OTn6+OOPtXfvXj377LN69dVXdffdd5/HlKfW0NCgb7/9VrNmzdJ1112nK6+88rT1hw8f1r59+5SVlXWeEp7agw8+qB49ehgdAwAMdabrUFe6BknSL37xC40ZM+Y8pAMAnEpr3gO1N177A4B/+vE158svv1SPHj20YMECo2MBPosVPMCPvPHGG6qrq5MkDRw48JR1//jHP5Sdna0jR47okksu0ZIlSzRhwoTzFfO0Nm/erKSkJA0ZMkT5+flnrO/du7cqKirOQ7IzmzdvnqfR1HyANwD4k9Zch7rSNUiSioqK1NDQIEnq1atXR8YDALSgte+B2huv/QHA//z0mhMQEKAdO3ZIkoKCggxMBvguk7ulfTUAAAAAAAAAAADQabFFGwAAAAAAAAAAgI+hwQMAAAAAAAAAAOBjaPAAAAAAAAAAAAD4GBo8AAAAAAAAAAAAPoYGDwAAAACfU15eLpPJpB07dnSax0pMTNSjjz7a4XkAAAAAQKLBAwAAAACnNWDAAFVWVmrYsGGSpPfee08mk0k//PCDscEAAAAA+DWL0QEAAAAAoLOqr6+X1WpV//79jY4CAAAAAF5YwQMAAACgU1q3bp1uuOEG9enTR6GhoUpNTdW+fftOWf/Xv/5Vl156qYKDg5WUlKRXX331pJU2q1at0i9+8QsFBQUpMjJSixcv9vockZGRevLJJ/Xb3/5WvXr10n//9397bdFWXl6upKQkSVLfvn1lMpl0zz33eD6+qalJ06dP1wUXXKD+/ftrzpw5Xp/fZDLphRdeUGpqqkJCQjR06FB98MEH2rt3rxITE9W9e3eNHDnS6+v8+OOPlZSUpJ49e6pXr1666qqr9OGHH7b9iQUAAADQJdDgAQAAANAp1dbWKiMjQx9++KHeffddBQQEaOzYsWpqajqptqysTOnp6bLZbPr444/1wAMP6PHHH/eq+eijj3T77bfr17/+tXbu3Kk5c+boD3/4g1asWOFVl5OTo+HDh+uf//yn/vCHP3jNDRgwQKtWrZIk7d69W5WVlXrmmWc886+++qq6d++urVu3Kjs7W/PmzVNxcbHX52huIO3YsUM///nP9Zvf/EYPPPCAZsyYoQ8//FBut1uTJ0/21N95552KiIjQtm3b9NFHH+mxxx5TYGBgm55TAAAAAF2Hye12u40OAQAAAABn8t133+nCCy/Uzp071aNHD0VFRemf//ynRowYoccee0xr1qzRzp07PfWzZs3SU089pe+//159+vTRnXfeqYMHD2r9+vWemunTp2vNmjX65JNPJP1nBc8vf/lLvfPOO56a8vJyr8d67733lJSU5Pm8zRITE+VyueR0Oj1j1157rUaPHq2nn35a0n9W8MyaNUtPPvmkJKm0tFTXX3+9Xn75Zd13332SpL/85S+69957VVdXJ0nq1auXnn32Wd19993t/IwCAAAA8GWs4AEAAADQKe3Zs0fjx4/XJZdcol69eikyMlKS9OWXX55Uu3v3bl1zzTVeY9dee63X/c8++0yjRo3yGhs1apT27Nkjl8vlGbv66qvbnPmKK67wuh8eHq4DBw6csiYsLEySFBMT4zV2/Phx1dTUSJIyMjI0YcIE3XTTTXr66adPu00dAAAAAP9BgwcAAABAp3Tbbbfp0KFDeumll7R161Zt3bpVklRfX9+hj9u9e/c2f+xPt04zmUwnbSn34xqTyXTKseaPmzNnjj755BPdeuut2rBhgy6//HKvFUYAAAAA/BMNHgAAAACdTnV1tXbv3q1Zs2bpxhtv1NChQ/X999+fsv6yyy7Thx9+6DW2bds2r/tDhw7V5s2bvcY2b96sIUOGyGw2tzqb1WqVJK9VPx1tyJAhmjp1qtavXy+73a5XXnnlvD02AAAAgM6JBg8AAACATqdv374KDQ3Viy++qL1792rDhg3KyMg4Zf0DDzygf//73/r973+vzz//XG+//bZWrFgh6f+viMnMzNS7776rJ598Up9//rleffVV/elPf1JWVtZZZRs0aJBMJpMKCwt18OBBHT16tM1f55nU1dVp8uTJeu+997R//35t3rxZ27Zt09ChQzvsMQEAAAD4Bho8AAAAADqdgIAA/eUvf9FHH32kYcOGaerUqVq0aNEp66OiopSfny+Hw6ErrrhCzz//vB5//HFJUlBQkCTpyiuv1Ntvv62//OUvGjZsmJ544gnNmzdP99xzz1llu/jiizV37lw99thjCgsL0+TJk9v8dZ6J2WxWdXW1fvvb32rIkCG6/fbbNWbMGM2dO7fDHhMAAACAbzC53W630SEAAAAAoL099dRTWrZsmb766iujowAAAABAu7MYHQAAAAAA2sPSpUt1zTXXKDQ0VJs3b9aiRYs6dHUNAAAAABiJBg8AAACALmHPnj2aP3++Dh06pIEDByozM1MzZswwOhYAAAAAdAi2aAMAAAAAAAAAAPAxAUYHAAAAAAAAAAAAwNmhwQMAAAAAAAAAAOBjaPAAAAAAAAAAAAD4GBo8AAAAAAAAAAAAPoYGDwAAAAAAAAAAgI+hwQMAAAAAAAAAAOBjaPAAAAAAAAAAAAD4GBo8AAAAAAAAAAAAPoYGDwAAAAAAAAAAgI/5fwru91RMZGVPAAAAAElFTkSuQmCC",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "# Show a box plot of the number of DecideAndOr events per algorithm\n",
+ "ax = decide_and_or_per_algorithm.boxplot(by='algorithms', column='DecideAndOr', figsize=(20, 10))\n",
+ "ax.set_ylim(0, 200)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " DecideAndOr | \n",
+ "
\n",
+ " \n",
+ " algorithms | \n",
+ " | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " ['qp'] | \n",
+ " 13.0 | \n",
+ "
\n",
+ " \n",
+ " ['greedy', 'qp'] | \n",
+ " 8.0 | \n",
+ "
\n",
+ " \n",
+ " ['greedy'] | \n",
+ " 0.0 | \n",
+ "
\n",
+ " \n",
+ " [] | \n",
+ " 0.0 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " DecideAndOr\n",
+ "algorithms \n",
+ "['qp'] 13.0\n",
+ "['greedy', 'qp'] 8.0\n",
+ "['greedy'] 0.0\n",
+ "[] 0.0"
+ ]
+ },
+ "execution_count": 10,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# Compute the median number of DecideAndOr events per algorithm\n",
+ "decide_and_or_per_algorithm.groupby('algorithms').median().sort_values(by='DecideAndOr', ascending=False)"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "env",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.11.2"
+ },
+ "orig_nbformat": 4
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/benchmark_silicon/Makefile b/benchmark_silicon/Makefile
new file mode 100644
index 00000000000..a1af4696b08
--- /dev/null
+++ b/benchmark_silicon/Makefile
@@ -0,0 +1,3 @@
+env:
+ python3 -m venv env
+ env/bin/pip install jupyter notebook mypy pandas pylint matplotlib z3-solver
diff --git a/benchmark_silicon/benchmark_silicon.py b/benchmark_silicon/benchmark_silicon.py
new file mode 100644
index 00000000000..724e7572910
--- /dev/null
+++ b/benchmark_silicon/benchmark_silicon.py
@@ -0,0 +1,357 @@
+#!/usr/bin/python3
+
+import argparse
+import os
+import glob
+from pathlib import Path
+import csv
+import subprocess
+import json
+import datetime
+
+def is_test_ignored(file_path):
+ for line in open(file_path):
+ if 'IgnoreFile(/silicon' in line:
+ return True
+ if 'IgnoreFile(/Silicon' in line:
+ return True
+ if 'IgnoreFile(/silver' in line:
+ return True
+ if 'IgnoreFile(/Silver' in line:
+ return True
+ return False
+
+class Test:
+
+ def __init__(self, identifier, file_path):
+ self.identifier = identifier
+ self.file_path = file_path
+ self.is_ignored = is_test_ignored(file_path)
+ self.args = None
+ self.result = None
+ self.stdout = None
+ self.stderr = None
+ self.start_time = None
+ self.end_time = None
+ self.duration = None
+ self.algorithms = []
+ self.wands = []
+ self.log_files = []
+ self.trace_files = []
+ self.event_kinds = []
+ self.smt2_events = []
+
+ def into_row(self):
+ return [
+ self.file_path,
+ self.is_ignored,
+ self.args,
+ self.result,
+ self.stdout,
+ self.stderr,
+ self.algorithms,
+ self.wands,
+ ]
+
+ def into_dict(self):
+ return {
+ 'identifier': self.identifier,
+ 'file_path': str(self.file_path),
+ 'is_ignored': self.is_ignored,
+ 'args': self.args,
+ 'result': self.result,
+ 'stdout': self.stdout,
+ 'stderr': self.stderr,
+ 'start_time': str(self.start_time) if self.start_time else None,
+ 'end_time': str(self.end_time) if self.end_time else None,
+ 'duration': self.duration.total_seconds() if self.duration else None,
+ 'algorithms': self.algorithms,
+ 'wands': self.wands,
+ 'log_files': self.log_files,
+ 'trace_files': self.trace_files,
+ 'event_kinds': self.event_kinds,
+ 'smt2_events': self.smt2_events,
+ }
+
+ def execute(
+ self,
+ viper_server_jar,
+ z3_exe,
+ temp_directory,
+ silicon_flags,
+ ):
+ """
+ java
+ -Xss1024m -Xmx4024m \\
+ -cp viper_tools/backends/viperserver.jar \\
+ viper.silicon.SiliconRunner \\
+ --z3Exe z3-4.8.7-x64-ubuntu-16.04/bin/z3 \\
+ --numberOfParallelVerifiers=1 \\
+ --logLevel TRACE \\
+ --tempDirectory log/viper_tmp/deadlock \\
+ --maskHeapMode \\
+ file
+ """
+ args = [
+ 'java',
+ '-Xss1024m',
+ '-Xmx4024m',
+ '-cp', viper_server_jar,
+ 'viper.silicon.SiliconRunner',
+ '--z3Exe', z3_exe,
+ '--numberOfParallelVerifiers=1',
+ '--logLevel', 'TRACE',
+ '--enableTempDirectory',
+ '--tempDirectory', temp_directory,
+ ] + silicon_flags + [self.file_path]
+ self.args = ' '.join(str(arg) for arg in args)
+ try:
+ self.stdout = os.path.join(temp_directory, 'stdout')
+ self.stderr = os.path.join(temp_directory, 'stderr')
+ stdout = open(self.stdout, 'w')
+ stderr = open(self.stderr, 'w')
+ self.start_time = datetime.datetime.now()
+ result = subprocess.run(
+ args,
+ timeout=120,
+ stdout=stdout,
+ stderr=stderr,
+ )
+ self.end_time = datetime.datetime.now()
+ self.duration = self.end_time - self.start_time
+ except subprocess.TimeoutExpired:
+ self.result = 'timeout'
+ if result.returncode == 0:
+ self.result = 'success'
+ else:
+ self.result = 'failure'
+
+ def analyze_log(self):
+ with open(self.stdout) as fp:
+ for line in fp:
+ if ' - Predicate ' in line:
+ suffix = line.split(' - Predicate ')[1].strip()
+ (predicate, algorithm) = suffix.split(' algorithm ')
+ self.algorithms.append((predicate, algorithm))
+ if ' - Field ' in line:
+ suffix = line.split(' - Field ')[1].strip()
+ (predicate, algorithm) = suffix.split(' algorithm ')
+ self.algorithms.append((predicate, algorithm))
+ if ' - Quantified wands: ' in line:
+ wands_count = line.split(' - Quantified wands: ')[1]
+ self.wands.append(int(wands_count))
+
+ def count_push_pop_operations(self, temp_directory):
+ for log_file in sorted(glob.glob(os.path.join(temp_directory, 'logfile-*.smt2'))):
+ push_count = 0
+ pop_count = 0
+ with open(log_file) as fp:
+ for line in fp:
+ if line.startswith('(push) ;'):
+ push_count += 1
+ if line.startswith('(pop) ;'):
+ pop_count += 1
+ self.smt2_events.append({
+ 'push': push_count,
+ 'pop': pop_count,
+ })
+
+ def generate_z3_traces(self, z3_exe, temp_directory):
+ for log_file in sorted(glob.glob(os.path.join(temp_directory, 'logfile-*.smt2'))):
+ self.log_files.append(log_file)
+ trace_file = log_file.replace('.smt2', '.trace')
+ self.trace_files.append(trace_file)
+ self.run_z3(z3_exe, log_file, trace_file)
+ assert os.path.exists(trace_file)
+
+ def run_z3(self, z3_exe, log_file, trace_file):
+ args = [
+ z3_exe,
+ 'trace=true',
+ 'proof=true',
+ 'trace-file-name=' + trace_file,
+ log_file,
+ ]
+ subprocess.run(
+ args,
+ timeout=600,
+ check=True,
+ stdout=subprocess.DEVNULL,
+ stderr=subprocess.DEVNULL,
+ )
+
+ def parce_z3_traces(self):
+ if os.path.exists('target/release/smt-log-analyzer'):
+ analyzer = 'target/release/smt-log-analyzer'
+ elif os.path.exists('target/debug/smt-log-analyzer'):
+ analyzer = 'target/debug/smt-log-analyzer'
+ else:
+ raise Exception('not found smt-log-analyzer')
+ for trace_file in self.trace_files:
+ args = [
+ analyzer,
+ trace_file,
+ ]
+ subprocess.run(
+ args,
+ timeout=120,
+ check=True,
+ stdout=subprocess.DEVNULL,
+ stderr=subprocess.DEVNULL,
+ )
+ self.parse_event_kinds(trace_file)
+
+ def parse_event_kinds(self, trace_file):
+ event_kinds = []
+ with open(trace_file + '.event-kinds.csv') as fp:
+ for line in fp:
+ (event, count) = line.strip().split(',')
+ if event == 'Event Kind':
+ continue
+ event_kinds.append((event, int(count)))
+ self.event_kinds.append(event_kinds)
+
+def collect_tests(viper_tests_path):
+ print(viper_tests_path, flush=True)
+ tests = []
+ for file_path in Path(viper_tests_path).rglob('*.vpr'):
+ test = Test(len(tests), file_path)
+ tests.append(test)
+ return tests
+
+def write_report_csv(tests, report_path):
+ with open(report_path, 'w') as fp:
+ writer = csv.writer(fp)
+ writer.writerow([
+ 'File',
+ 'Ignored',
+ 'Command',
+ 'Result',
+ 'Stdout',
+ 'Stderr',
+ 'Algorithms',
+ 'Wands',
+ ])
+ for test in tests:
+ writer.writerow(test.into_row())
+
+def write_report_json(tests, report_path):
+ with open(report_path, 'w') as fp:
+ json.dump([test.into_dict() for test in tests], fp, sort_keys=True, indent=4)
+
+def execute_tests(
+ tests,
+ workspace,
+ viper_server_jar,
+ z3_exe,
+ silicon_flags,
+ ):
+ for test in tests:
+ if not test.is_ignored:
+ print(test.file_path, datetime.datetime.now(), flush=True)
+ try:
+ temp_directory = os.path.join(workspace, f'test-{test.identifier:04}')
+ os.mkdir(temp_directory)
+ test.execute(
+ viper_server_jar,
+ z3_exe,
+ temp_directory,
+ silicon_flags,
+ )
+ test.analyze_log()
+ test.count_push_pop_operations(temp_directory)
+ test.generate_z3_traces(z3_exe, temp_directory)
+ test.parce_z3_traces() # Call Rust SMT analyzer and use its CSV.
+ except Exception as e:
+ print(e)
+
+def analyze_test_results(workspace):
+ tests = []
+ for directory in os.listdir(workspace):
+ if not directory.startswith('test-'):
+ continue
+ temp_directory = os.path.join(workspace, directory)
+ log_file = os.path.join(temp_directory, 'logfile-00.smt2')
+ if not os.path.exists(log_file):
+ continue
+ file_path = None
+ with open(log_file) as fp:
+ for line in fp:
+ if line.startswith('; Input file:'):
+ file_path = line.split('; Input file:')[1].strip()
+ break
+ if file_path is None:
+ continue
+ identifier = int(directory.split('-')[1])
+ test = Test(identifier, file_path)
+ tests.append(test)
+ test.stdout = os.path.join(temp_directory, 'stdout')
+ test.stderr = os.path.join(temp_directory, 'stderr')
+ test.analyze_log()
+ test.log_files = list(sorted(glob.glob(os.path.join(temp_directory, 'logfile-*.smt2'))))
+ test.trace_files = list(sorted(glob.glob(os.path.join(temp_directory, 'logfile-*.trace'))))
+ for trace_file in test.trace_files:
+ try:
+ test.parse_event_kinds(trace_file)
+ except Exception as e:
+ print(e)
+ return tests
+
+def parse_args():
+ parser = argparse.ArgumentParser(description="Benchmark Silicon Z3 statistics.")
+ parser.add_argument(
+ "--viper-server-jar",
+ help="path of the Viper server JAR",
+ default='viper_tools/backends/viperserver_meilers_silicarbon.jar',
+ )
+ parser.add_argument(
+ "--z3-exe",
+ help="path to Z3",
+ default='viper_tools/z3/bin/z3',
+ )
+ parser.add_argument(
+ "--viper-tests",
+ help="path to Viper tests folder",
+ default='../viperserver/silicon/silver/src/test/resources/',
+ )
+ parser.add_argument(
+ "--report-csv",
+ help="output path of the CSV file",
+ default='../workspace/report.csv',
+ )
+ parser.add_argument(
+ "--report-json",
+ help="output path of the JSON file",
+ default='../workspace/report.json',
+ )
+ parser.add_argument(
+ "--workspace",
+ help="the workspace directory",
+ default='../workspace',
+ )
+ return parser.parse_args()
+
+def main():
+ args = parse_args()
+ if not os.path.exists(args.workspace):
+ tests = collect_tests(args.viper_tests)
+ os.mkdir(args.workspace)
+ try:
+ execute_tests(
+ tests,
+ args.workspace,
+ args.viper_server_jar,
+ args.z3_exe,
+ [], #['--maskHeapMode'],
+ )
+ finally:
+ write_report_csv(tests, args.report_csv)
+ write_report_json(tests, args.report_json)
+ else:
+ tests = analyze_test_results(args.workspace)
+ write_report_csv(tests, args.report_csv)
+ write_report_json(tests, args.report_json)
+
+if __name__ == '__main__':
+ main()
+
diff --git a/benchmark_silicon/generate_sums.py b/benchmark_silicon/generate_sums.py
new file mode 100644
index 00000000000..651103476c2
--- /dev/null
+++ b/benchmark_silicon/generate_sums.py
@@ -0,0 +1,196 @@
+#!/usr/bin/python3
+
+import z3
+import datetime
+
+class State:
+ def __init__(self):
+ self.address_sort = z3.DeclareSort('Address')
+ self.perm_sort = z3.RealSort()
+ self._full_permission = z3.RealVal("1")
+ self._no_permission = z3.RealVal("0")
+ self.solver = z3.Solver()
+ self.locations = []
+ self.permissions = []
+ self.sum = []
+ self.non_negativity_assumptions = []
+ self.exhaled_location = self.fresh_location()
+
+ def fresh_location(self):
+ location = z3.Const(f"address${len(self.locations)}", self.address_sort)
+ self.locations.append(location)
+ return location
+
+ def fresh_permission(self):
+ permission = z3.Const(f"permission${len(self.permissions)}", self.perm_sort)
+ self.permissions.append(permission)
+ return permission
+
+ def full_permission(self):
+ return self._full_permission
+
+ def add_summand(self, location, permission):
+ self.sum.append(
+ z3.If(self.exhaled_location == location, permission, self._no_permission)
+ )
+
+ def is_non_negative_assertion(self):
+ sum_expr = self._no_permission
+ for summand in self.sum:
+ sum_expr = sum_expr + summand
+ return sum_expr >= self._no_permission
+
+ def generate_sum(self):
+ sum_expr = self._no_permission
+ for summand in self.sum:
+ sum_expr = sum_expr + summand
+ return sum_expr
+
+ def is_full_assertion(self):
+ sum_expr = self._no_permission
+ for summand in self.sum:
+ sum_expr = sum_expr + summand
+ return sum_expr >= self._full_permission
+
+ def add_non_negativity_assumption(self):
+ self.solver.push()
+ assertion = self.is_non_negative_assertion()
+ self.solver.add(assertion)
+
+ def check_assertion(self, assertion):
+ assertion = z3.Not(assertion)
+ # print(assertion)
+ self.solver.push()
+ self.solver.add(assertion)
+ print("checking: {assertion}")
+# print(self.solver)
+ start = datetime.datetime.now()
+ result = self.solver.check()
+ self.solver.pop()
+ end = datetime.datetime.now()
+ print(f" start: {start}")
+ print(f" end: {end}")
+ print(f" duration: {end-start}")
+ return result
+
+ def check_assertion2(self, assertion):
+ assertion = z3.Not(assertion)
+ solver = z3.Solver()
+ solver.add(assertion)
+ start = datetime.datetime.now()
+ result = solver.check()
+ end = datetime.datetime.now()
+ print(f" start: {start}")
+ print(f" end: {end}")
+ print(f" duration: {end-start}")
+ return result
+
+def construct_sum(exhaled_location, locations, permission, no_permission):
+ sum_expr = no_permission
+ for location in locations:
+ sum_expr = sum_expr + z3.If(
+ exhaled_location == location,
+ permission,
+ no_permission,
+ )
+ return sum_expr
+
+def check_size(size, add_group_assumptions):
+# print(f"size: {size}")
+ state = State()
+ locations = []
+ for _ in range(size):
+ locations.append(state.fresh_location())
+ assertion = z3.BoolVal(True)
+ for (i, exhaled_location) in enumerate(locations):
+ # print(i, exhaled_location)
+ inhaled_sum = construct_sum(
+ exhaled_location, locations, state._full_permission, state._no_permission)
+ # print(inhaled_sum)
+ exhaled_sum = construct_sum(
+ exhaled_location, locations[:i], -state._full_permission, state._no_permission)
+ # print(exhaled_sum)
+ check = inhaled_sum + exhaled_sum >= state._full_permission
+ # print(check)
+ assertion = z3.And(assertion, check)
+
+ if add_group_assumptions:
+ for (j, location_group) in enumerate(locations):
+ inhaled = z3.If(
+ exhaled_location == location_group,
+ state._full_permission,
+ state._no_permission,
+ )
+ exhaled = z3.If(
+ exhaled_location == location_group,
+ -state._full_permission,
+ state._no_permission,
+ )
+ if j < i:
+ conjunct = inhaled + exhaled >= 0
+ else:
+ conjunct = inhaled >= 0
+ # print(conjunct)
+ assertion = z3.And(assertion, conjunct)
+
+# print(assertion)
+ assertion = z3.Not(assertion)
+ state.solver.add(assertion)
+ start = datetime.datetime.now()
+ result = state.solver.check()
+ end = datetime.datetime.now()
+# print(f" start: {start}")
+# print(f" end: {end}")
+# print(f" duration: {end-start}")
+# print(result)
+ print(f"Size {size} completed in {end-start} with {result}")
+ # add_group_assumptions=False
+ # Size 1 completed in 0:00:00.005373
+ # Size 2 completed in 0:00:00.006233
+ # Size 3 completed in 0:00:00.006431
+ # Size 4 completed in 0:00:00.009251
+ # Size 5 completed in 0:00:00.011879
+ # Size 6 completed in 0:00:00.013903
+ # Size 7 completed in 0:00:00.018198
+ # Size 8 completed in 0:00:00.020426
+ # Size 9 completed in 0:00:00.027054
+ # Size 10 completed in 0:00:00.045473
+ # Size 11 completed in 0:00:00.078226
+ # Size 12 completed in 0:00:00.149595
+ # Size 13 completed in 0:00:00.280547
+ # Size 14 completed in 0:00:00.558921
+ # Size 15 completed in 0:00:01.145783
+ # Size 16 completed in 0:00:02.419031
+ # Size 17 completed in 0:00:05.444189
+ # Size 18 completed in 0:00:10.202696
+ # Size 19 completed in 0:00:28.442166
+ # Size 20 completed in 0:01:32.388904
+ # add_group_assumptions=True
+ # Size 1 completed in 0:00:00.006661
+ # Size 2 completed in 0:00:00.008673
+ # Size 3 completed in 0:00:00.008395
+ # Size 4 completed in 0:00:00.012773
+ # Size 5 completed in 0:00:00.012729
+ # Size 6 completed in 0:00:00.014022
+ # Size 7 completed in 0:00:00.012290
+ # Size 8 completed in 0:00:00.016343
+ # Size 9 completed in 0:00:00.021220
+ # Size 10 completed in 0:00:00.024776
+ # Size 11 completed in 0:00:00.032785
+ # Size 12 completed in 0:00:00.041238
+ # Size 13 completed in 0:00:00.046568
+ # Size 14 completed in 0:00:00.069082
+ # Size 15 completed in 0:00:00.457555
+ # Size 16 completed in 0:00:00.212668
+ # Size 17 completed in 0:00:00.139427
+ # Size 18 completed in 0:00:00.176176
+ # Size 19 completed in 0:00:00.180726
+
+def main():
+ state = State()
+
+ for i in range(1, 20):
+ check_size(i, True)
+
+if __name__ == '__main__':
+ main()
diff --git a/benchmark_silicon/generate_sums2.py b/benchmark_silicon/generate_sums2.py
new file mode 100644
index 00000000000..7b0b247991c
--- /dev/null
+++ b/benchmark_silicon/generate_sums2.py
@@ -0,0 +1,243 @@
+#!env/bin/python3
+
+# Based on https://microsoft.github.io/z3guide/programming/Example%20Programs/User%20Propagator/
+
+import datetime
+import union_find
+import z3
+
+address_sort = z3.DeclareSort('Address')
+permission_mask_sort = z3.DeclareSort('PermissionMask')
+perm_sort = z3.RealSort()
+prop_sort = z3.BoolSort()
+perm_empty = z3.PropagateFunction(
+ "perm_empty", permission_mask_sort, prop_sort)
+perm_update = z3.PropagateFunction(
+ "perm_update", permission_mask_sort, address_sort, perm_sort, permission_mask_sort, prop_sort)
+# perm_lookup = z3.PropagateFunction(
+# "perm_lookup", permission_mask_sort, address_sort, perm_sort)
+perm_read = z3.PropagateFunction(
+ "perm_read", permission_mask_sort, address_sort, perm_sort, prop_sort)
+no_permission = z3.RealVal("0")
+full_permission = z3.RealVal("1")
+
+def location(index):
+ return z3.Const(f"address${index}", address_sort)
+permission_mask_counter = 0
+def perm_mask():
+ global permission_mask_counter
+ permission_mask_counter += 1
+ return z3.Const(f"perm_mask${permission_mask_counter}", permission_mask_sort)
+perm_counter = 0
+def perm_amount():
+ global perm_counter
+ perm_counter += 1
+ return z3.Const(f"perm_amount${perm_counter}", perm_sort)
+
+class PermissionGrouping(z3.UserPropagateBase):
+
+ def __init__(self, s=None, ctx=None, group_terms=False):
+ z3.UserPropagateBase.__init__(self, s, ctx)
+ self.add_fixed(lambda x, v : self._fixed(x, v))
+ self.add_final(lambda : self._final())
+ self.add_eq(lambda x, y : self._eq(x, y))
+ self.add_created(lambda t : self._created(t))
+ self.decide = None # It seems that UserPropagateBase is missing a field declaration. Monkey Patch for the resque!
+ self.add_decide(lambda t : self._decide(t))
+ self._empty_masks = set()
+ self._mask_derived_from = {}
+ self._group_terms = group_terms
+ self.push_count = 0
+ self.pop_count = 0
+ self.decide_count = 0
+ self.lim = []
+ self.trail = []
+ self.uf = union_find.UnionFind(self.trail)
+
+ def push(self):
+ self.push_count += 1
+ self.lim += [len(self.trail)]
+
+ def pop(self, n):
+ self.pop_count += n
+ head = self.lim[len(self.lim) - n]
+ while len(self.trail) > head:
+ self.trail[-1]()
+ self.trail.pop(-1)
+ self.lim = self.lim[0:len(self.lim)-n]
+
+ def _decide(self, _):
+ # This callback seems to be broken in the current version of z3.
+ self.decide_count += 1
+
+ def fresh(self, new_ctx):
+ TODO
+
+ def _fixed(self, x, v):
+ # print("fixed: ", x, " := ", v)
+ assert z3.is_true(v)
+ if x.decl().eq(perm_empty):
+ mask = x.arg(0)
+ assert mask in self._empty_masks
+ elif x.decl().eq(perm_update):
+ mask = x.arg(0)
+ address = x.arg(1)
+ permission = x.arg(2)
+ new_mask = x.arg(3)
+ self._mask_derived_from[new_mask] = (mask, address, permission)
+ # elif x.decl().eq(perm_lookup):
+ # mask = x.arg(0)
+ # address = x.arg(1)
+ # self.add(mask)
+ # self.add(address)
+ # self.add(x)
+ elif x.decl().eq(perm_read):
+ mask = x.arg(0)
+ address = x.arg(1)
+ value = x.arg(2)
+ groups = {}
+ def compute_sum(mask):
+ if mask in self._empty_masks:
+ return 0
+ else:
+ (update_mask, update_address, update_permission) = self._mask_derived_from[mask]
+ summand = z3.If(address == update_address, update_permission, no_permission)
+ if self._group_terms:
+ node = self.uf.node(update_address)
+ root_term = self.uf.find(node).term
+ if root_term not in groups:
+ groups[root_term] = []
+ groups[root_term] += [(summand, update_permission)]
+ return summand + compute_sum(update_mask)
+ assumption = value == compute_sum(mask)
+ if self._group_terms:
+ # print("groups:", groups)
+ for group in groups.values():
+ sum_expression = z3.Sum([summand for (summand, _) in group])
+ sum_value = z3.simplify(sum([value for (_, value) in group]))
+ if sum_value.eq(no_permission) or sum_value.eq(full_permission):
+ assumption = z3.And(assumption, sum_expression >= 0)
+ # print("learned assumption:", assumption)
+ self.propagate(assumption, [x])
+ else:
+ TODO
+
+ def _final(self):
+ TODO
+
+ def _eq(self, x, y):
+ # print(f"_eq!: {x} {v}")
+ self.uf.merge(x, y)
+
+ def _created(self, t):
+ if t.decl().eq(perm_empty):
+ mask = t.arg(0)
+ self.add(mask)
+ self._empty_masks.add(mask)
+ elif t.decl().eq(perm_update):
+ mask = t.arg(0)
+ address = t.arg(1)
+ permission = t.arg(2)
+ new_mask = t.arg(3)
+ self.uf.node(address)
+ self.add(mask)
+ self.add(address)
+ self.add(permission)
+ self.add(new_mask)
+ # elif t.decl().eq(perm_lookup):
+ # mask = t.arg(0)
+ # address = t.arg(1)
+ # self.add(mask)
+ # self.add(address)
+ # self.add(t)
+ elif t.decl().eq(perm_read):
+ mask = t.arg(0)
+ address = t.arg(1)
+ self.uf.node(address)
+ value = t.arg(2)
+ self.add(mask)
+ self.add(address)
+ self.add(value)
+ else:
+ TODO
+
+def check_size(size, group_terms):
+ solver = z3.Solver()
+ pg = PermissionGrouping(solver, group_terms=group_terms)
+
+ mask = perm_mask()
+ solver.add(perm_empty(mask))
+
+ addresses = []
+ for i in range(size):
+ address = location(i)
+ addresses.append(address)
+ # inhale acc(address)
+ new_mask = perm_mask()
+ solver.add(perm_update(mask, address, 1.0, new_mask))
+ mask = new_mask
+
+ checks = z3.BoolVal(True)
+ for (i, address) in enumerate(addresses):
+ # exhale acc(address)
+ value = perm_amount()
+ solver.add(perm_read(mask, address, value))
+ checks = z3.And(checks, value >= 1)
+ new_mask = perm_mask()
+ solver.add(perm_update(mask, address, -1.0, new_mask))
+ mask = new_mask
+
+ solver.add(z3.Not(checks))
+
+ start = datetime.datetime.now()
+ result = solver.check()
+ end = datetime.datetime.now()
+
+ # print(solver)
+ # print(solver.check())
+ print(f"Size {size} completed in {end-start} (decide: {pg.decide_count} push: {pg.push_count} pop: {pg.pop_count}) with {result}")
+
+def main():
+ # check_size(3, False)
+ for i in range(3, 20):
+ check_size(i, True)
+ # group_terms=False
+ # Size 3 completed in 0:00:00.006197 (push: 11 pop: 11) with unsat
+ # Size 4 completed in 0:00:00.016547 (push: 50 pop: 50) with unsat
+ # Size 5 completed in 0:00:00.026013 (push: 136 pop: 136) with unsat
+ # Size 6 completed in 0:00:00.049699 (push: 264 pop: 264) with unsat
+ # Size 7 completed in 0:00:00.082637 (push: 403 pop: 403) with unsat
+ # Size 8 completed in 0:00:00.138415 (push: 599 pop: 599) with unsat
+ # Size 9 completed in 0:00:00.225748 (push: 914 pop: 914) with unsat
+ # Size 10 completed in 0:00:00.387808 (push: 1476 pop: 1476) with unsat
+ # Size 11 completed in 0:00:00.695106 (push: 2542 pop: 2542) with unsat
+ # Size 12 completed in 0:00:01.142290 (push: 3737 pop: 3737) with unsat
+ # Size 13 completed in 0:00:02.020809 (push: 6086 pop: 6086) with unsat
+ # Size 14 completed in 0:00:03.464235 (push: 10355 pop: 10355) with unsat
+ # Size 15 completed in 0:00:06.745241 (push: 17012 pop: 17012) with unsat
+ # Size 16 completed in 0:00:12.223822 (push: 31490 pop: 31490) with unsat
+ # Size 17 completed in 0:00:28.458352 (push: 71376 pop: 71376) with unsat
+ # Size 18 completed in 0:01:07.913775 (push: 163310 pop: 163310) with unsat
+ # Size 19 completed in 0:02:37.331497 (push: 370474 pop: 370474) with unsat
+ # group_terms=True
+ # Size 3 completed in 0:00:00.008096 (push: 8 pop: 8) with unsat
+ # Size 4 completed in 0:00:00.014301 (push: 26 pop: 26) with unsat
+ # Size 5 completed in 0:00:00.023871 (push: 59 pop: 59) with unsat
+ # Size 6 completed in 0:00:00.036188 (push: 126 pop: 126) with unsat
+ # Size 7 completed in 0:00:00.062952 (push: 312 pop: 312) with unsat
+ # Size 8 completed in 0:00:00.073902 (push: 335 pop: 335) with unsat
+ # Size 9 completed in 0:00:00.110649 (push: 625 pop: 625) with unsat
+ # Size 10 completed in 0:00:00.137818 (push: 733 pop: 733) with unsat
+ # Size 11 completed in 0:00:00.163656 (push: 687 pop: 687) with unsat
+ # Size 12 completed in 0:00:00.170364 (push: 1058 pop: 1058) with unsat
+ # Size 13 completed in 0:00:00.226454 (push: 1301 pop: 1301) with unsat
+ # Size 14 completed in 0:00:00.251802 (push: 1556 pop: 1556) with unsat
+ # Size 15 completed in 0:00:00.342975 (push: 1925 pop: 1925) with unsat
+ # Size 16 completed in 0:00:00.341066 (push: 2791 pop: 2791) with unsat
+ # Size 17 completed in 0:00:00.394620 (push: 2708 pop: 2708) with unsat
+ # Size 18 completed in 0:00:00.448467 (push: 3258 pop: 3258) with unsat
+ # Size 19 completed in 0:00:00.471308 (push: 2988 pop: 2988) with unsat
+
+
+if __name__ == '__main__':
+ main()
diff --git a/benchmark_silicon/union_find.py b/benchmark_silicon/union_find.py
new file mode 100644
index 00000000000..ffd54d00db1
--- /dev/null
+++ b/benchmark_silicon/union_find.py
@@ -0,0 +1,98 @@
+# Taken from https://microsoft.github.io/z3guide/programming/Example%20Programs/User%20Propagator/
+
+class Node:
+ def __init__(self, a):
+ self.term = a
+ self.id = a.get_id()
+ self.root = self
+ self.size = 1
+ self.value = None
+
+ def __eq__(self, other):
+ return self.id == other.id
+
+ def __ne__(self, other):
+ return self.id != other.id
+
+ def to_string(self):
+ return f"{self.term} -> r:{self.root.term}"
+
+ def __str__(self):
+ return self.to_string()
+
+class UnionFind:
+ def __init__(self, trail):
+ self._nodes = {}
+ self.trail = trail
+
+ def node(self, a):
+ if a in self._nodes:
+ return self._nodes[a]
+ n = Node(a)
+ self._nodes[a] = n
+ def undo():
+ del self._nodes[a]
+ self.trail.append(undo)
+ return n
+
+ def merge(self, a, b):
+ a = self.node(a)
+ b = self.node(b)
+ a = self.find(a)
+ b = self.find(b)
+ if a == b:
+ return
+ if a.size < b.size:
+ a, b = b, a
+ if a.value is not None and b.value is not None:
+ print("Merging two values", a, a.value, b, b.value)
+ os._exit()
+ value = a.value
+ if b.value is not None:
+ value = b.value
+ old_root = b.root
+ old_asize = a.size
+ old_bvalue = b.value
+ old_avalue = a.value
+ b.root = a.root
+ b.value = value
+ a.value = value
+ a.size += b.size
+ def undo():
+ b.root = old_root
+ a.size = old_asize
+ b.value = old_bvalue
+ a.value = old_avalue
+ self.trail.append(undo)
+
+ # skip path compression to keep the example basic
+ def find(self, a):
+ assert isinstance(a, Node)
+ root = a.root
+ while root != root.root:
+ root = root.root
+ return root
+
+ def set_value(self, a):
+ n = self.find(self.node(a))
+ if n.value is not None:
+ return
+ def undo():
+ n.value = None
+ n.value = a
+ self.trail.append(undo)
+
+ def get_value(self, a):
+ return self.find(self.node(a)).value
+
+ def root_term(self, a):
+ return self.find(self.node(a)).term
+
+ def __str__(self):
+ return self.to_string()
+
+ def __repr__(self):
+ return self.to_string()
+
+ def to_string(self):
+ return "\n".join([n.to_string() for t, n in self._nodes.items()])
diff --git a/jni-gen/systest/tests/jvm_builtin_classes.rs b/jni-gen/systest/tests/jvm_builtin_classes.rs
index 523fe7d12ed..b40bf76d8be 100644
--- a/jni-gen/systest/tests/jvm_builtin_classes.rs
+++ b/jni-gen/systest/tests/jvm_builtin_classes.rs
@@ -10,7 +10,7 @@ fn string_to_jobject<'a>(env: &JNIEnv<'a>, string: &str) -> JNIResult(env: &JNIEnv<'a>, obj: JObject) -> JNIResult {
+fn jobject_to_string(env: &JNIEnv<'_>, obj: JObject) -> JNIResult {
Ok(String::from(env.get_string(JString::from(obj))?))
}
diff --git a/prusti-common/src/vir/low_to_viper/ast.rs b/prusti-common/src/vir/low_to_viper/ast.rs
index 6e56e887b01..9fcbf8c7edb 100644
--- a/prusti-common/src/vir/low_to_viper/ast.rs
+++ b/prusti-common/src/vir/low_to_viper/ast.rs
@@ -1,4 +1,5 @@
-use super::{Context, ToViper, ToViperDecl};
+use super::{calculate_hash_with_position, Context, ToViper, ToViperDecl};
+use std::collections::BTreeMap;
use viper::{self, AstFactory};
use vir::low::ast::{
expression::{self, Expression},
@@ -11,17 +12,22 @@ use vir::low::ast::{
};
impl<'a, 'v> ToViper<'v, viper::Predicate<'v>> for &'a PredicateDecl {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Predicate<'v> {
- ast.predicate(
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Predicate<'v> {
+ let mut annotations = BTreeMap::new();
+ if &self.name != "LifetimeToken" {
+ annotations.insert("qpresource".to_string(), Vec::new());
+ }
+ ast.predicate_with_annotations(
&self.name,
&self.parameters.to_viper_decl(context, ast),
self.body.as_ref().map(|body| body.to_viper(context, ast)),
+ &annotations,
)
}
}
impl<'a, 'v> ToViper<'v, viper::Function<'v>> for &'a FunctionDecl {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Function<'v> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Function<'v> {
ast.function(
&self.name,
&self.parameters.to_viper_decl(context, ast),
@@ -35,7 +41,7 @@ impl<'a, 'v> ToViper<'v, viper::Function<'v>> for &'a FunctionDecl {
}
impl<'v> ToViper<'v, Vec>> for Vec {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> Vec> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> Vec> {
self.iter()
.map(|statement| statement.to_viper(context, ast))
.collect()
@@ -43,9 +49,14 @@ impl<'v> ToViper<'v, Vec>> for Vec {
}
impl<'v> ToViper<'v, viper::Stmt<'v>> for Statement {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Stmt<'v> {
- match self {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Stmt<'v> {
+ let statement_hash = calculate_hash_with_position(self);
+ if let Some(viper_statement) = context.get_cached_statement(statement_hash, self) {
+ return viper_statement;
+ }
+ let viper_statement = match self {
Statement::Comment(statement) => statement.to_viper(context, ast),
+ Statement::Label(statement) => statement.to_viper(context, ast),
Statement::LogEvent(statement) => statement.to_viper(context, ast),
Statement::Assume(statement) => statement.to_viper(context, ast),
Statement::Assert(statement) => statement.to_viper(context, ast),
@@ -57,18 +68,32 @@ impl<'v> ToViper<'v, viper::Stmt<'v>> for Statement {
Statement::Conditional(statement) => statement.to_viper(context, ast),
Statement::MethodCall(statement) => statement.to_viper(context, ast),
Statement::Assign(statement) => statement.to_viper(context, ast),
- }
+ Statement::MaterializePredicate(statement) => {
+ unreachable!("should have been purified out: {statement}")
+ }
+ Statement::CaseSplit(statement) => {
+ unreachable!("should have been purified out: {statement}")
+ }
+ };
+ context.cache_statement(statement_hash, self, viper_statement);
+ viper_statement
}
}
impl<'v> ToViper<'v, viper::Stmt<'v>> for statement::Comment {
- fn to_viper(&self, _context: Context, ast: &AstFactory<'v>) -> viper::Stmt<'v> {
+ fn to_viper(&self, _context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Stmt<'v> {
ast.comment(&self.comment)
}
}
+impl<'v> ToViper<'v, viper::Stmt<'v>> for statement::Label {
+ fn to_viper(&self, _context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Stmt<'v> {
+ ast.label(&self.label, &[])
+ }
+}
+
impl<'v> ToViper<'v, viper::Stmt<'v>> for statement::LogEvent {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Stmt<'v> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Stmt<'v> {
assert!(
self.expression.is_domain_func_app(),
"The log event has to be a domain function application: {self}"
@@ -78,7 +103,7 @@ impl<'v> ToViper<'v, viper::Stmt<'v>> for statement::LogEvent {
}
impl<'v> ToViper<'v, viper::Stmt<'v>> for statement::Assume {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Stmt<'v> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Stmt<'v> {
assert!(
!self.position.is_default(),
"Statement with default position: {self}"
@@ -91,7 +116,7 @@ impl<'v> ToViper<'v, viper::Stmt<'v>> for statement::Assume {
}
impl<'v> ToViper<'v, viper::Stmt<'v>> for statement::Assert {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Stmt<'v> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Stmt<'v> {
assert!(
!self.position.is_default(),
"Statement with default position: {self}"
@@ -104,7 +129,7 @@ impl<'v> ToViper<'v, viper::Stmt<'v>> for statement::Assert {
}
impl<'v> ToViper<'v, viper::Stmt<'v>> for statement::Inhale {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Stmt<'v> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Stmt<'v> {
assert!(
!self.position.is_default(),
"Statement with default position: {self}"
@@ -117,7 +142,7 @@ impl<'v> ToViper<'v, viper::Stmt<'v>> for statement::Inhale {
}
impl<'v> ToViper<'v, viper::Stmt<'v>> for statement::Exhale {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Stmt<'v> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Stmt<'v> {
assert!(
!self.position.is_default(),
"Statement with default position: {self}"
@@ -130,11 +155,16 @@ impl<'v> ToViper<'v, viper::Stmt<'v>> for statement::Exhale {
}
impl<'v> ToViper<'v, viper::Stmt<'v>> for statement::Fold {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Stmt<'v> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Stmt<'v> {
assert!(
!self.position.is_default(),
"Statement with default position: {self}"
);
+ assert!(
+ self.expression.is_predicate_access_predicate(),
+ "fold {}",
+ self.expression
+ );
ast.fold_with_pos(
self.expression.to_viper(context, ast),
self.position.to_viper(context, ast),
@@ -143,11 +173,16 @@ impl<'v> ToViper<'v, viper::Stmt<'v>> for statement::Fold {
}
impl<'v> ToViper<'v, viper::Stmt<'v>> for statement::Unfold {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Stmt<'v> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Stmt<'v> {
assert!(
!self.position.is_default(),
"Statement with default position: {self}"
);
+ assert!(
+ self.expression.is_predicate_access_predicate(),
+ "unfold {}",
+ self.expression
+ );
ast.unfold_with_pos(
self.expression.to_viper(context, ast),
self.position.to_viper(context, ast),
@@ -156,7 +191,7 @@ impl<'v> ToViper<'v, viper::Stmt<'v>> for statement::Unfold {
}
impl<'v> ToViper<'v, viper::Stmt<'v>> for statement::ApplyMagicWand {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Stmt<'v> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Stmt<'v> {
assert!(
!self.position.is_default(),
"Statement with default position: {self}"
@@ -169,7 +204,7 @@ impl<'v> ToViper<'v, viper::Stmt<'v>> for statement::ApplyMagicWand {
}
impl<'v> ToViper<'v, viper::Stmt<'v>> for statement::Conditional {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Stmt<'v> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Stmt<'v> {
assert!(
!self.position.is_default(),
"Statement with default position: {self}"
@@ -183,7 +218,7 @@ impl<'v> ToViper<'v, viper::Stmt<'v>> for statement::Conditional {
}
impl<'v> ToViper<'v, viper::Stmt<'v>> for statement::MethodCall {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Stmt<'v> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Stmt<'v> {
assert!(
!self.position.is_default(),
"Statement with default position: {self}"
@@ -198,7 +233,11 @@ impl<'v> ToViper<'v, viper::Stmt<'v>> for statement::MethodCall {
}
impl<'v> ToViper<'v, viper::Stmt<'v>> for statement::Assign {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Stmt<'v> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Stmt<'v> {
+ assert!(
+ !self.position.is_default(),
+ "Statement with default position: {self}"
+ );
let target_expression = Expression::local(self.target.clone(), self.position);
ast.abstract_assign(
target_expression.to_viper(context, ast),
@@ -208,7 +247,7 @@ impl<'v> ToViper<'v, viper::Stmt<'v>> for statement::Assign {
}
impl<'v> ToViper<'v, Vec>> for Vec {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> Vec> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> Vec> {
self.iter()
.map(|expression| expression.to_viper(context, ast))
.collect()
@@ -216,7 +255,11 @@ impl<'v> ToViper<'v, Vec>> for Vec {
}
impl<'v> ToViper<'v, viper::Expr<'v>> for Expression {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Expr<'v> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Expr<'v> {
+ let expression_hash = calculate_hash_with_position(self);
+ if let Some(viper_expression) = context.get_cached_expression(expression_hash, self) {
+ return viper_expression;
+ }
let expression = match self {
Expression::Local(expression) => expression.to_viper(context, ast),
// Expression::Field(expression) => expression.to_viper(context, ast),
@@ -225,30 +268,32 @@ impl<'v> ToViper<'v, viper::Expr<'v>> for Expression {
Expression::MagicWand(expression) => expression.to_viper(context, ast),
Expression::PredicateAccessPredicate(expression) => expression.to_viper(context, ast),
// Expression::FieldAccessPredicate(expression) => expression.to_viper(context, ast),
- // Expression::Unfolding(expression) => expression.to_viper(context, ast),
+ Expression::Unfolding(expression) => expression.to_viper(context, ast),
Expression::UnaryOp(expression) => expression.to_viper(context, ast),
Expression::BinaryOp(expression) => expression.to_viper(context, ast),
Expression::PermBinaryOp(expression) => expression.to_viper(context, ast),
Expression::ContainerOp(expression) => expression.to_viper(context, ast),
Expression::Conditional(expression) => expression.to_viper(context, ast),
Expression::Quantifier(expression) => expression.to_viper(context, ast),
- // Expression::LetExpr(expression) => expression.to_viper(context, ast),
+ Expression::LetExpr(expression) => expression.to_viper(context, ast),
Expression::FuncApp(expression) => expression.to_viper(context, ast),
Expression::DomainFuncApp(expression) => expression.to_viper(context, ast),
// Expression::InhaleExhale(expression) => expression.to_viper(context, ast),
x => unimplemented!("{:?}", x),
};
- if crate::config::simplify_encoding() {
+ let viper_expression = if crate::config::simplify_encoding() {
ast.simplified_expression(expression)
} else {
expression
- }
+ };
+ context.cache_expression(expression_hash, self, viper_expression);
+ viper_expression
}
}
impl<'v> ToViper<'v, viper::Expr<'v>> for expression::Local {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Expr<'v> {
- if self.variable.name == "__result" {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Expr<'v> {
+ if self.variable.is_result_variable() {
ast.result_with_pos(
self.variable.ty.to_viper(context, ast),
self.position.to_viper(context, ast),
@@ -264,7 +309,7 @@ impl<'v> ToViper<'v, viper::Expr<'v>> for expression::Local {
}
impl<'v> ToViper<'v, viper::Expr<'v>> for expression::LabelledOld {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Expr<'v> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Expr<'v> {
if let Some(label) = &self.label {
ast.labelled_old_with_pos(
self.base.to_viper(context, ast),
@@ -278,7 +323,7 @@ impl<'v> ToViper<'v, viper::Expr<'v>> for expression::LabelledOld {
}
impl<'v> ToViper<'v, viper::Expr<'v>> for expression::Constant {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Expr<'v> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Expr<'v> {
match &self.ty {
Type::Int => match &self.value {
expression::ConstantValue::Bool(_) => {
@@ -327,7 +372,7 @@ impl<'v> ToViper<'v, viper::Expr<'v>> for expression::Constant {
}
impl<'v> ToViper<'v, viper::Expr<'v>> for expression::MagicWand {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Expr<'v> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Expr<'v> {
ast.magic_wand_with_pos(
self.left.to_viper(context, ast),
self.right.to_viper(context, ast),
@@ -337,7 +382,7 @@ impl<'v> ToViper<'v, viper::Expr<'v>> for expression::MagicWand {
}
impl<'v> ToViper<'v, viper::Expr<'v>> for expression::PredicateAccessPredicate {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Expr<'v> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Expr<'v> {
let location = ast.predicate_access(&self.arguments.to_viper(context, ast), &self.name);
if context.inside_trigger {
location
@@ -351,8 +396,18 @@ impl<'v> ToViper<'v, viper::Expr<'v>> for expression::PredicateAccessPredicate {
}
}
+impl<'v> ToViper<'v, viper::Expr<'v>> for expression::Unfolding {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Expr<'v> {
+ ast.unfolding_with_pos(
+ self.predicate.to_viper(context, ast),
+ self.base.to_viper(context, ast),
+ self.position.to_viper(context, ast),
+ )
+ }
+}
+
impl<'v> ToViper<'v, viper::Expr<'v>> for expression::UnaryOp {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Expr<'v> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Expr<'v> {
match self.op_kind {
expression::UnaryOpKind::Minus => ast.minus_with_pos(
self.argument.to_viper(context, ast),
@@ -367,7 +422,7 @@ impl<'v> ToViper<'v, viper::Expr<'v>> for expression::UnaryOp {
}
impl<'v> ToViper<'v, viper::Expr<'v>> for expression::BinaryOp {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Expr<'v> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Expr<'v> {
match self.op_kind {
expression::BinaryOpKind::EqCmp => ast.eq_cmp_with_pos(
self.left.to_viper(context, ast),
@@ -444,7 +499,7 @@ impl<'v> ToViper<'v, viper::Expr<'v>> for expression::BinaryOp {
}
impl<'v> ToViper<'v, viper::Expr<'v>> for expression::PermBinaryOp {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Expr<'v> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Expr<'v> {
match self.op_kind {
expression::PermBinaryOpKind::Add => ast.perm_add(
self.left.to_viper(context, ast),
@@ -467,7 +522,7 @@ impl<'v> ToViper<'v, viper::Expr<'v>> for expression::PermBinaryOp {
}
impl<'v> ToViper<'v, viper::Expr<'v>> for expression::Conditional {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Expr<'v> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Expr<'v> {
ast.cond_exp_with_pos(
self.guard.to_viper(context, ast),
self.then_expr.to_viper(context, ast),
@@ -478,7 +533,7 @@ impl<'v> ToViper<'v, viper::Expr<'v>> for expression::Conditional {
}
impl<'v> ToViper<'v, viper::Expr<'v>> for expression::Quantifier {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Expr<'v> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Expr<'v> {
let variables = self.variables.to_viper_decl(context, ast);
let triggers = self
.triggers
@@ -499,17 +554,30 @@ impl<'v> ToViper<'v, viper::Expr<'v>> for expression::Quantifier {
}
impl<'v, 'a> ToViper<'v, viper::Trigger<'v>> for (&'a expression::Trigger, Position) {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Trigger<'v> {
- let trigger_context = context.set_inside_trigger();
- ast.trigger_with_pos(
- &self.0.terms.to_viper(trigger_context, ast)[..],
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Trigger<'v> {
+ let old_value = context.set_inside_trigger();
+ let trigger = ast.trigger_with_pos(
+ &self.0.terms.to_viper(context, ast)[..],
self.1.to_viper(context, ast),
+ );
+ context.reset_inside_trigger(old_value);
+ trigger
+ }
+}
+
+impl<'v> ToViper<'v, viper::Expr<'v>> for expression::LetExpr {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Expr<'v> {
+ ast.let_expr_with_pos(
+ self.variable.to_viper_decl(context, ast),
+ self.def.to_viper(context, ast),
+ self.body.to_viper(context, ast),
+ self.position.to_viper(context, ast),
)
}
}
impl<'v> ToViper<'v, viper::Expr<'v>> for expression::FuncApp {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Expr<'v> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Expr<'v> {
ast.func_app(
&self.function_name,
&self.arguments.to_viper(context, ast),
@@ -520,7 +588,7 @@ impl<'v> ToViper<'v, viper::Expr<'v>> for expression::FuncApp {
}
impl<'v> ToViper<'v, viper::Expr<'v>> for expression::DomainFuncApp {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Expr<'v> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Expr<'v> {
ast.domain_func_app2(
&self.function_name,
&self.arguments.to_viper(context, ast),
@@ -533,81 +601,142 @@ impl<'v> ToViper<'v, viper::Expr<'v>> for expression::DomainFuncApp {
}
impl<'v> ToViper<'v, viper::Expr<'v>> for expression::ContainerOp {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Expr<'v> {
- let element_type = || match &self.container_type {
- Type::Seq(ty::Seq { element_type, .. })
- | Type::Set(ty::Set { element_type, .. })
- | Type::MultiSet(ty::MultiSet { element_type, .. }) => {
- element_type.to_viper(context, ast)
- }
- _ => unreachable!("{}", self.container_type),
- };
- let key_value_types = || match &self.container_type {
- Type::Map(ty::Map { key_type, val_type }) => {
- let key_type = key_type.to_viper(context, ast);
- let val_type = val_type.to_viper(context, ast);
- (key_type, val_type)
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Expr<'v> {
+ fn element_type<'v>(
+ container_type: &Type,
+ context: &mut Context<'v>,
+ ast: &AstFactory<'v>,
+ ) -> viper::Type<'v> {
+ match container_type {
+ Type::Seq(ty::Seq { element_type, .. })
+ | Type::Set(ty::Set { element_type, .. })
+ | Type::MultiSet(ty::MultiSet { element_type, .. }) => {
+ element_type.to_viper(context, ast)
+ }
+ _ => unreachable!(),
}
- _ => unreachable!(),
- };
- let arg = |idx| (&self.operands[idx] as &Expression).to_viper(context, ast);
- let args = || {
- self.operands
+ }
+ // let element_type = || match &self.container_type {
+ // Type::Seq(ty::Seq { element_type, .. })
+ // | Type::Set(ty::Set { element_type, .. })
+ // | Type::MultiSet(ty::MultiSet { element_type, .. }) => {
+ // element_type.to_viper(context, ast)
+ // }
+ // _ => unreachable!("{}", self.container_type),
+ // };
+ // let key_value_types = || match &self.container_type {
+ // Type::Map(ty::Map { key_type, val_type }) => {
+ // let key_type = key_type.to_viper(context, ast);
+ // let val_type = val_type.to_viper(context, ast);
+ // (key_type, val_type)
+ // }
+ // _ => unreachable!(),
+ // };
+ fn arg<'v>(
+ this: &expression::ContainerOp,
+ idx: usize,
+ context: &mut Context<'v>,
+ ast: &AstFactory<'v>,
+ ) -> viper::Expr<'v> {
+ (&this.operands[idx] as &Expression).to_viper(context, ast)
+ }
+ fn args<'v>(
+ this: &expression::ContainerOp,
+ context: &mut Context<'v>,
+ ast: &AstFactory<'v>,
+ ) -> Vec> {
+ this.operands
.iter()
.map(|operand| operand.to_viper(context, ast))
.collect::>()
- };
+ }
+ // let arg = |idx| (&self.operands[idx] as &Expression).to_viper(context, ast);
+ // let args = || {
+ // self.operands
+ // .iter()
+ // .map(|operand| operand.to_viper(context, ast))
+ // .collect::>()
+ // };
match self.kind {
- expression::ContainerOpKind::SeqEmpty => ast.empty_seq(element_type()),
+ expression::ContainerOpKind::SeqEmpty => {
+ ast.empty_seq(element_type(&self.container_type, context, ast))
+ }
expression::ContainerOpKind::SeqConstructor => {
- let elements = args();
+ let elements = args(self, context, ast);
if elements.is_empty() {
- ast.empty_seq(element_type())
+ ast.empty_seq(element_type(&self.container_type, context, ast))
} else {
ast.explicit_seq(&elements)
}
}
- expression::ContainerOpKind::SeqIndex => ast.seq_index(arg(0), arg(1)),
- expression::ContainerOpKind::SeqConcat => ast.seq_append(arg(0), arg(1)),
- expression::ContainerOpKind::SeqLen => ast.seq_length(arg(0)),
+ expression::ContainerOpKind::SeqIndex => {
+ ast.seq_index(arg(self, 0, context, ast), arg(self, 1, context, ast))
+ }
+ expression::ContainerOpKind::SeqConcat => {
+ ast.seq_append(arg(self, 0, context, ast), arg(self, 1, context, ast))
+ }
+ expression::ContainerOpKind::SeqLen => ast.seq_length(arg(self, 0, context, ast)),
expression::ContainerOpKind::MapEmpty => {
- let (key_ty, val_ty) = key_value_types();
- ast.empty_map(key_ty, val_ty)
+ // let (key_ty, val_ty) = key_value_types();
+ let Type::Map(ty::Map { key_type, val_type }) = &self.container_type else {
+ unreachable!()
+ };
+ let key_type = key_type.to_viper(context, ast);
+ let val_type = val_type.to_viper(context, ast);
+ ast.empty_map(key_type, val_type)
+ }
+ expression::ContainerOpKind::MapUpdate => ast.update_map(
+ arg(self, 0, context, ast),
+ arg(self, 1, context, ast),
+ arg(self, 2, context, ast),
+ ),
+ expression::ContainerOpKind::MapContains => {
+ ast.map_contains(arg(self, 0, context, ast), arg(self, 1, context, ast))
+ }
+ expression::ContainerOpKind::MapLookup => {
+ ast.lookup_map(arg(self, 0, context, ast), arg(self, 1, context, ast))
+ }
+ expression::ContainerOpKind::MapLen => ast.map_len(arg(self, 0, context, ast)),
+ expression::ContainerOpKind::SetEmpty => {
+ ast.empty_set(element_type(&self.container_type, context, ast))
}
- expression::ContainerOpKind::MapUpdate => ast.update_map(arg(0), arg(1), arg(2)),
- expression::ContainerOpKind::MapContains => ast.map_contains(arg(0), arg(1)),
- expression::ContainerOpKind::MapLookup => ast.lookup_map(arg(0), arg(1)),
- expression::ContainerOpKind::MapLen => ast.map_len(arg(0)),
- expression::ContainerOpKind::SetEmpty => ast.empty_set(element_type()),
expression::ContainerOpKind::SetConstructor => {
- let elements = args();
+ let elements = args(self, context, ast);
if elements.is_empty() {
- ast.empty_set(element_type())
+ ast.empty_set(element_type(&self.container_type, context, ast))
} else {
ast.explicit_set(&elements)
}
}
expression::ContainerOpKind::SetUnion | expression::ContainerOpKind::MultiSetUnion => {
- ast.any_set_union(arg(0), arg(1))
+ ast.any_set_union(arg(self, 0, context, ast), arg(self, 1, context, ast))
}
expression::ContainerOpKind::SetIntersection
| expression::ContainerOpKind::MultiSetIntersection => {
- ast.any_set_intersection(arg(0), arg(1))
+ ast.any_set_intersection(arg(self, 0, context, ast), arg(self, 1, context, ast))
}
expression::ContainerOpKind::SetSubset
- | expression::ContainerOpKind::MultiSetSubset => ast.any_set_subset(arg(0), arg(1)),
+ | expression::ContainerOpKind::MultiSetSubset => {
+ ast.any_set_subset(arg(self, 0, context, ast), arg(self, 1, context, ast))
+ }
expression::ContainerOpKind::SetMinus | expression::ContainerOpKind::MultiSetMinus => {
- ast.any_set_minus(arg(0), arg(1))
+ ast.any_set_minus(arg(self, 0, context, ast), arg(self, 1, context, ast))
}
expression::ContainerOpKind::SetContains
- | expression::ContainerOpKind::MultiSetContains => ast.any_set_contains(arg(0), arg(1)),
+ | expression::ContainerOpKind::MultiSetContains => {
+ ast.any_set_contains(arg(self, 0, context, ast), arg(self, 1, context, ast))
+ }
expression::ContainerOpKind::SetCardinality
- | expression::ContainerOpKind::MultiSetCardinality => ast.any_set_cardinality(arg(0)),
- expression::ContainerOpKind::MultiSetEmpty => ast.empty_multiset(element_type()),
+ | expression::ContainerOpKind::MultiSetCardinality => {
+ ast.any_set_cardinality(arg(self, 0, context, ast))
+ }
+ expression::ContainerOpKind::MultiSetEmpty => {
+ ast.empty_multiset(element_type(&self.container_type, context, ast))
+ }
expression::ContainerOpKind::MultiSetConstructor => {
- let elements = args();
+ let elements = args(self, context, ast);
if elements.is_empty() {
- ast.empty_multiset(element_type())
+ ast.empty_multiset(element_type(&self.container_type, context, ast))
} else {
ast.explicit_multiset(&elements)
}
@@ -617,13 +746,13 @@ impl<'v> ToViper<'v, viper::Expr<'v>> for expression::ContainerOp {
}
impl<'v> ToViper<'v, viper::Position<'v>> for Position {
- fn to_viper(&self, _context: Context, ast: &AstFactory<'v>) -> viper::Position<'v> {
+ fn to_viper(&self, _context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Position<'v> {
ast.identifier_position(self.line, self.column, self.id.to_string())
}
}
impl<'v> ToViper<'v, viper::Type<'v>> for Type {
- fn to_viper(&self, _context: Context, ast: &AstFactory<'v>) -> viper::Type<'v> {
+ fn to_viper(&self, _context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Type<'v> {
match self {
Type::Int => ast.int_type(),
Type::Bool => ast.bool_type(),
@@ -659,7 +788,7 @@ impl<'v> ToViper<'v, viper::Type<'v>> for Type {
impl<'v> ToViperDecl<'v, Vec>> for Vec {
fn to_viper_decl(
&self,
- context: Context,
+ context: &mut Context<'v>,
ast: &AstFactory<'v>,
) -> Vec> {
self.iter()
@@ -669,7 +798,11 @@ impl<'v> ToViperDecl<'v, Vec>> for Vec {
}
impl<'v> ToViperDecl<'v, viper::LocalVarDecl<'v>> for VariableDecl {
- fn to_viper_decl(&self, context: Context, ast: &AstFactory<'v>) -> viper::LocalVarDecl<'v> {
+ fn to_viper_decl(
+ &self,
+ context: &mut Context<'v>,
+ ast: &AstFactory<'v>,
+ ) -> viper::LocalVarDecl<'v> {
ast.local_var_decl(&self.name, self.ty.to_viper(context, ast))
}
}
diff --git a/prusti-common/src/vir/low_to_viper/cfg.rs b/prusti-common/src/vir/low_to_viper/cfg.rs
index 95a937d337c..6244c35504c 100644
--- a/prusti-common/src/vir/low_to_viper/cfg.rs
+++ b/prusti-common/src/vir/low_to_viper/cfg.rs
@@ -1,6 +1,7 @@
use super::{Context, ToViper, ToViperDecl};
use viper::{self, AstFactory};
use vir::{
+ common::cfg::Cfg,
legacy::RETURN_LABEL,
low::{
ast::position::Position,
@@ -9,27 +10,32 @@ use vir::{
};
impl<'a, 'v> ToViper<'v, viper::Method<'v>> for &'a ProcedureDecl {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Method<'v> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Method<'v> {
let mut statements: Vec = vec![];
let mut declarations: Vec = vec![];
for local in &self.locals {
declarations.push(local.to_viper_decl(context, ast).into());
}
- for block in &self.basic_blocks {
- declarations.push(block.label.to_viper_decl(context, ast).into());
- statements.push(block.label.to_viper(context, ast));
+ let traversal_order = self.get_topological_sort();
+ for label in &traversal_order {
+ let block = self.basic_blocks.get(label).unwrap();
+ declarations.push(label.to_viper_decl(context, ast).into());
+ statements.push(label.to_viper(context, ast));
statements.extend(block.statements.to_viper(context, ast));
statements.push(block.successor.to_viper(context, ast));
}
statements.push(ast.label(RETURN_LABEL, &[]));
declarations.push(ast.label(RETURN_LABEL, &[]).into());
+ for label in &self.custom_labels {
+ declarations.push(label.to_viper_decl(context, ast).into());
+ }
let body = Some(ast.seqn(&statements, &declarations));
ast.method(&self.name, &[], &[], &[], &[], body)
}
}
impl<'v> ToViper<'v, viper::Stmt<'v>> for Successor {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Stmt<'v> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Stmt<'v> {
match self {
Successor::Goto(target) => ast.goto(&target.name),
Successor::GotoSwitch(targets) => {
@@ -54,19 +60,19 @@ impl<'v> ToViper<'v, viper::Stmt<'v>> for Successor {
}
impl<'v> ToViperDecl<'v, viper::Stmt<'v>> for Label {
- fn to_viper_decl(&self, _context: Context, ast: &AstFactory<'v>) -> viper::Stmt<'v> {
+ fn to_viper_decl(&self, _context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Stmt<'v> {
ast.label(&self.name, &[])
}
}
impl<'v> ToViper<'v, viper::Stmt<'v>> for Label {
- fn to_viper(&self, _context: Context, ast: &AstFactory<'v>) -> viper::Stmt<'v> {
+ fn to_viper(&self, _context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Stmt<'v> {
ast.label(&self.name, &[])
}
}
impl<'a, 'v> ToViper<'v, viper::Method<'v>> for &'a MethodDecl {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Method<'v> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Method<'v> {
let body = self
.body
.as_ref()
diff --git a/prusti-common/src/vir/low_to_viper/domain.rs b/prusti-common/src/vir/low_to_viper/domain.rs
index 6a3e4dee445..26221cc415a 100644
--- a/prusti-common/src/vir/low_to_viper/domain.rs
+++ b/prusti-common/src/vir/low_to_viper/domain.rs
@@ -1,20 +1,26 @@
use super::{Context, ToViper, ToViperDecl};
use viper::{self, AstFactory};
-use vir::low::{DomainAxiomDecl, DomainDecl, DomainFunctionDecl};
+use vir::low::{DomainAxiomDecl, DomainDecl, DomainFunctionDecl, DomainRewriteRuleDecl};
impl<'a, 'v> ToViper<'v, viper::Domain<'v>> for &'a DomainDecl {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Domain<'v> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Domain<'v> {
+ let mut axioms = (&self.name, &self.axioms).to_viper(context, ast);
+ axioms.extend((&self.name, &self.rewrite_rules).to_viper(context, ast));
ast.domain(
&self.name,
&(&self.name, &self.functions).to_viper(context, ast),
- &(&self.name, &self.axioms).to_viper(context, ast),
+ &axioms,
&[],
)
}
}
impl<'a, 'v> ToViper<'v, Vec>> for (&'a String, &'a Vec) {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> Vec> {
+ fn to_viper(
+ &self,
+ context: &mut Context<'v>,
+ ast: &AstFactory<'v>,
+ ) -> Vec> {
self.1
.iter()
.map(|function| (self.0, function).to_viper(context, ast))
@@ -23,7 +29,7 @@ impl<'a, 'v> ToViper<'v, Vec>> for (&'a String, &'a Vec ToViper<'v, viper::DomainFunc<'v>> for (&'a String, &'a DomainFunctionDecl) {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::DomainFunc<'v> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::DomainFunc<'v> {
let (domain_name, function) = self;
ast.domain_func(
&function.name,
@@ -38,7 +44,11 @@ impl<'a, 'v> ToViper<'v, viper::DomainFunc<'v>> for (&'a String, &'a DomainFunct
impl<'a, 'v> ToViper<'v, Vec>>
for (&'a String, &'a Vec)
{
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> Vec> {
+ fn to_viper(
+ &self,
+ context: &mut Context<'v>,
+ ast: &AstFactory<'v>,
+ ) -> Vec> {
self.1
.iter()
.map(|axiom| (self.0, axiom).to_viper(context, ast))
@@ -47,7 +57,11 @@ impl<'a, 'v> ToViper<'v, Vec>>
}
impl<'a, 'v> ToViper<'v, viper::NamedDomainAxiom<'v>> for (&'a String, &'a DomainAxiomDecl) {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::NamedDomainAxiom<'v> {
+ fn to_viper(
+ &self,
+ context: &mut Context<'v>,
+ ast: &AstFactory<'v>,
+ ) -> viper::NamedDomainAxiom<'v> {
let (domain_name, axiom) = self;
if let Some(comment) = &axiom.comment {
ast.named_domain_axiom_with_comment(
@@ -61,3 +75,41 @@ impl<'a, 'v> ToViper<'v, viper::NamedDomainAxiom<'v>> for (&'a String, &'a Domai
}
}
}
+
+impl<'a, 'v> ToViper<'v, Vec>>
+ for (&'a String, &'a Vec)
+{
+ fn to_viper(
+ &self,
+ context: &mut Context<'v>,
+ ast: &AstFactory<'v>,
+ ) -> Vec> {
+ self.1
+ .iter()
+ .filter(|rule| !rule.egg_only)
+ .map(|axiom| (self.0, axiom).to_viper(context, ast))
+ .collect()
+ }
+}
+
+impl<'a, 'v> ToViper<'v, viper::NamedDomainAxiom<'v>> for (&'a String, &'a DomainRewriteRuleDecl) {
+ fn to_viper(
+ &self,
+ context: &mut Context<'v>,
+ ast: &AstFactory<'v>,
+ ) -> viper::NamedDomainAxiom<'v> {
+ let (domain_name, rewrite_rule) = self;
+ assert!(!rewrite_rule.egg_only);
+ let axiom = rewrite_rule.convert_into_axiom();
+ if let Some(comment) = &axiom.comment {
+ ast.named_domain_axiom_with_comment(
+ &axiom.name,
+ axiom.body.to_viper(context, ast),
+ domain_name,
+ comment,
+ )
+ } else {
+ ast.named_domain_axiom(&axiom.name, axiom.body.to_viper(context, ast), domain_name)
+ }
+ }
+}
diff --git a/prusti-common/src/vir/low_to_viper/mod.rs b/prusti-common/src/vir/low_to_viper/mod.rs
index 147cc6cf2dc..992acec505c 100644
--- a/prusti-common/src/vir/low_to_viper/mod.rs
+++ b/prusti-common/src/vir/low_to_viper/mod.rs
@@ -1,26 +1,114 @@
+use rustc_hash::FxHashMap;
use viper::AstFactory;
+use vir::{common::traits::HashWithPosition, low as vir_low};
mod ast;
mod cfg;
mod domain;
mod program;
-#[derive(Clone, Copy, Default, Debug)]
-pub struct Context {
+#[derive(Clone, Default)]
+pub struct Context<'v> {
inside_trigger: bool,
+ expression_cache: FxHashMap<(u64, bool), viper::Expr<'v>>,
+ expression_cache_validation: FxHashMap<(u64, bool), vir_low::Expression>,
+ statement_cache: FxHashMap>,
+ statement_cache_validation: FxHashMap,
}
-impl Context {
- pub fn set_inside_trigger(mut self) -> Self {
+impl<'v> Context<'v> {
+ pub fn set_inside_trigger(&mut self) -> bool {
+ let old_value = self.inside_trigger;
self.inside_trigger = true;
- self
+ old_value
+ }
+
+ pub fn reset_inside_trigger(&mut self, old_value: bool) {
+ self.inside_trigger = old_value;
+ }
+
+ pub fn get_cached_expression(
+ &self,
+ expression_hash: u64,
+ expression: &vir_low::Expression,
+ ) -> Option> {
+ let viper_expression = self
+ .expression_cache
+ .get(&(expression_hash, self.inside_trigger))
+ .cloned();
+ if cfg!(debug_assertions) && viper_expression.is_some() {
+ let cached_expression = self
+ .expression_cache_validation
+ .get(&(expression_hash, self.inside_trigger))
+ .unwrap();
+ assert_eq!(cached_expression, expression);
+ }
+ viper_expression
+ }
+
+ fn cache_expression(
+ &mut self,
+ expression_hash: u64,
+ expression: &vir_low::Expression,
+ viper_expression: viper::Expr<'v>,
+ ) {
+ if cfg!(debug_assertions) {
+ assert!(self
+ .expression_cache_validation
+ .insert((expression_hash, self.inside_trigger), expression.clone())
+ .is_none());
+ }
+ assert!(self
+ .expression_cache
+ .insert((expression_hash, self.inside_trigger), viper_expression)
+ .is_none());
+ }
+
+ pub fn get_cached_statement(
+ &self,
+ statement_hash: u64,
+ statement: &vir_low::Statement,
+ ) -> Option> {
+ let viper_statement = self.statement_cache.get(&statement_hash).cloned();
+ if cfg!(debug_assertions) && viper_statement.is_some() {
+ let cached_statement = self
+ .statement_cache_validation
+ .get(&statement_hash)
+ .unwrap();
+ assert_eq!(cached_statement, statement);
+ }
+ viper_statement
+ }
+
+ fn cache_statement(
+ &mut self,
+ statement_hash: u64,
+ statement: &vir_low::Statement,
+ viper_statement: viper::Stmt<'v>,
+ ) {
+ if cfg!(debug_assertions) {
+ assert!(self
+ .statement_cache_validation
+ .insert(statement_hash, statement.clone())
+ .is_none());
+ }
+ assert!(self
+ .statement_cache
+ .insert(statement_hash, viper_statement)
+ .is_none());
}
}
pub trait ToViper<'v, T> {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> T;
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> T;
}
pub trait ToViperDecl<'v, T> {
- fn to_viper_decl(&self, context: Context, ast: &AstFactory<'v>) -> T;
+ fn to_viper_decl(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> T;
+}
+
+pub(super) fn calculate_hash_with_position(t: &T) -> u64 {
+ let mut s = std::collections::hash_map::DefaultHasher::new();
+ HashWithPosition::hash(t, &mut s);
+ std::hash::Hasher::finish(&s)
}
diff --git a/prusti-common/src/vir/low_to_viper/program.rs b/prusti-common/src/vir/low_to_viper/program.rs
index 3aa9743a897..fe441154481 100644
--- a/prusti-common/src/vir/low_to_viper/program.rs
+++ b/prusti-common/src/vir/low_to_viper/program.rs
@@ -3,7 +3,7 @@ use viper::{self, AstFactory};
use vir::low::program::Program;
impl<'v> ToViper<'v, viper::Program<'v>> for Program {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Program<'v> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Program<'v> {
let Program {
name: _,
check_mode: _,
@@ -17,11 +17,11 @@ impl<'v> ToViper<'v, viper::Program<'v>> for Program {
.iter()
.map(|domain| domain.to_viper(context, ast))
.collect();
- let viper_methods: Vec<_> = procedures
+ let mut viper_methods: Vec<_> = procedures
.iter()
.map(|procedure| procedure.to_viper(context, ast))
- .chain(methods.iter().map(|method| method.to_viper(context, ast)))
.collect();
+ viper_methods.extend(methods.iter().map(|method| method.to_viper(context, ast)));
let viper_predicates: Vec<_> = predicates
.iter()
.map(|predicate| predicate.to_viper(context, ast))
diff --git a/prusti-common/src/vir/optimizations/folding/expressions.rs b/prusti-common/src/vir/optimizations/folding/expressions.rs
index 40dd44d3cfd..9efda1f1a0f 100644
--- a/prusti-common/src/vir/optimizations/folding/expressions.rs
+++ b/prusti-common/src/vir/optimizations/folding/expressions.rs
@@ -23,6 +23,7 @@ use crate::{
use log::{debug, trace};
use rustc_hash::{FxHashMap, FxHashSet};
use std::{cmp::Ordering, mem};
+use vir::common::builtin_constants::DISCRIMINANT_FIELD_NAME;
pub trait FoldingOptimizer {
#[must_use]
@@ -180,7 +181,7 @@ fn check_requirements_conflict(
ast::PlaceComponent::Variant(..),
ast::PlaceComponent::Field(ast::Field { name, .. }, _),
) => {
- if name == "discriminant" {
+ if name == DISCRIMINANT_FIELD_NAME {
debug!("guarded permission: {} {}", place1, place2);
// If we are checking discriminant, this means that the
// permission is guarded.
diff --git a/prusti-common/src/vir/program.rs b/prusti-common/src/vir/program.rs
index c7bc8765128..a06113f781d 100644
--- a/prusti-common/src/vir/program.rs
+++ b/prusti-common/src/vir/program.rs
@@ -21,18 +21,20 @@ impl Program {
}
}
pub fn get_check_mode(&self) -> vir::common::check_mode::CheckMode {
+ // FIXME: Remove because this is not needed anymore.
match self {
- Program::Legacy(_) => vir::common::check_mode::CheckMode::Both,
+ Program::Legacy(_) => vir::common::check_mode::CheckMode::MemorySafetyWithFunctional,
Program::Low(program) => program.check_mode,
}
}
pub fn get_name_with_check_mode(&self) -> String {
+ // FIXME: Remove because this is not needed anymore.
format!("{}-{}", self.get_name(), self.get_check_mode())
}
}
impl<'v> ToViper<'v, viper::Program<'v>> for Program {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Program<'v> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Program<'v> {
match self {
Program::Legacy(program) => program.to_viper(context, ast),
Program::Low(program) => program.to_viper(context, ast),
diff --git a/prusti-common/src/vir/to_viper.rs b/prusti-common/src/vir/to_viper.rs
index 3d0d814e6e7..4f34c066b9b 100644
--- a/prusti-common/src/vir/to_viper.rs
+++ b/prusti-common/src/vir/to_viper.rs
@@ -21,7 +21,7 @@ use vir::common::identifier::WithIdentifier;
impl<'v> ToViper<'v, viper::Program<'v>> for Program {
#[tracing::instrument(name = "Program::to_viper", level = "debug", skip_all)]
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Program<'v> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Program<'v> {
let mut domains = self.domains.to_viper(context, ast);
domains.extend(self.backend_types.to_viper(context, ast));
let fields = self.fields.to_viper(context, ast);
@@ -92,13 +92,13 @@ impl<'v> ToViper<'v, viper::Position<'v>> for Position {
#[tracing::instrument(name = "Position::to_viper", level = "trace", skip_all, fields(
line = %self.line(), column = %self.column(), id = %self.id()
))]
- fn to_viper(&self, _context: Context, ast: &AstFactory<'v>) -> viper::Position<'v> {
+ fn to_viper(&self, _context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Position<'v> {
ast.identifier_position(self.line(), self.column(), self.id().to_string())
}
}
impl<'v> ToViper<'v, viper::Type<'v>> for Type {
- fn to_viper(&self, _context: Context, ast: &AstFactory<'v>) -> viper::Type<'v> {
+ fn to_viper(&self, _context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Type<'v> {
match self {
Type::Int => ast.int_type(),
Type::Bool => ast.bool_type(),
@@ -130,8 +130,8 @@ impl<'v> ToViper<'v, viper::Type<'v>> for Type {
}
impl<'v, 'a, 'b> ToViper<'v, viper::Expr<'v>> for (&'a LocalVar, &'b Position) {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Expr<'v> {
- if self.0.name == "__result" {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Expr<'v> {
+ if self.0.name == vir::common::builtin_constants::RESULT_VARIABLE_NAME {
ast.result_with_pos(
self.0.typ.to_viper(context, ast),
self.1.to_viper(context, ast),
@@ -147,20 +147,24 @@ impl<'v, 'a, 'b> ToViper<'v, viper::Expr<'v>> for (&'a LocalVar, &'b Position) {
}
impl<'v> ToViperDecl<'v, viper::LocalVarDecl<'v>> for LocalVar {
- fn to_viper_decl(&self, context: Context, ast: &AstFactory<'v>) -> viper::LocalVarDecl<'v> {
+ fn to_viper_decl(
+ &self,
+ context: &mut Context<'v>,
+ ast: &AstFactory<'v>,
+ ) -> viper::LocalVarDecl<'v> {
ast.local_var_decl(&self.name, self.typ.to_viper(context, ast))
}
}
impl<'v> ToViper<'v, viper::Field<'v>> for Field {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Field<'v> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Field<'v> {
ast.field(&self.name, self.typ.to_viper(context, ast))
}
}
impl<'v> ToViper<'v, viper::Stmt<'v>> for Stmt {
#[tracing::instrument(name = "Stmt::to_viper", level = "trace", skip(context, ast))]
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Stmt<'v> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Stmt<'v> {
match self {
Stmt::Comment(ref comment) => ast.comment(comment),
Stmt::Label(ref label) => ast.label(label, &[]),
@@ -231,10 +235,15 @@ impl<'v> ToViper<'v, viper::Stmt<'v>> for Stmt {
// access to the needed paths.
fn stmt_to_viper_in_packge<'v>(
stmt: &Stmt,
- context: Context,
+ context: &mut Context<'v>,
ast: &AstFactory<'v>,
) -> viper::Stmt<'v> {
- let create_footprint_asserts = |expr: &Expr, perm| -> Vec {
+ fn create_footprint_asserts<'v>(
+ context: &mut Context<'v>,
+ ast: &AstFactory<'v>,
+ expr: &Expr,
+ perm: PermAmount,
+ ) -> Vec> {
expr.compute_footprint(perm)
.into_iter()
.map(|access| {
@@ -243,10 +252,11 @@ impl<'v> ToViper<'v, viper::Stmt<'v>> for Stmt {
assert.to_viper(context, ast)
})
.collect()
- };
+ }
match stmt {
Stmt::Assign(ref lhs, ref rhs, _) => {
- let mut stmts = create_footprint_asserts(rhs, PermAmount::Read);
+ let mut stmts =
+ create_footprint_asserts(context, ast, rhs, PermAmount::Read);
stmts.push(ast.abstract_assign(
lhs.to_viper(context, ast),
rhs.to_viper(context, ast),
@@ -255,7 +265,8 @@ impl<'v> ToViper<'v, viper::Stmt<'v>> for Stmt {
}
Stmt::Exhale(ref expr, ref pos) => {
assert!(!pos.is_default());
- let mut stmts = create_footprint_asserts(expr, PermAmount::Read);
+ let mut stmts =
+ create_footprint_asserts(context, ast, expr, PermAmount::Read);
stmts.push(
ast.exhale(expr.to_viper(context, ast), pos.to_viper(context, ast)),
);
@@ -265,7 +276,8 @@ impl<'v> ToViper<'v, viper::Stmt<'v>> for Stmt {
assert_eq!(args.len(), 1);
let place = &args[0];
assert!(place.is_place());
- let mut stmts = create_footprint_asserts(place, PermAmount::Read);
+ let mut stmts =
+ create_footprint_asserts(context, ast, place, PermAmount::Read);
stmts.push(ast.fold_with_pos(
ast.predicate_access_predicate_with_pos(
ast.predicate_access_with_pos(
@@ -346,7 +358,7 @@ impl<'v> ToViper<'v, viper::Stmt<'v>> for Stmt {
}
impl<'v> ToViper<'v, viper::Expr<'v>> for PermAmount {
- fn to_viper(&self, _context: Context, ast: &AstFactory<'v>) -> viper::Expr<'v> {
+ fn to_viper(&self, _context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Expr<'v> {
match self {
PermAmount::Write => ast.full_perm(),
PermAmount::Read => ast.func_app("read$", &[], ast.perm_type(), ast.no_position()),
@@ -360,7 +372,7 @@ impl<'v> ToViper<'v, viper::Expr<'v>> for PermAmount {
impl<'v> ToViper<'v, viper::Expr<'v>> for Expr {
#[tracing::instrument(name = "Expr::to_viper", level = "trace", skip(context, ast))]
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Expr<'v> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Expr<'v> {
let expr = match self {
Expr::Local(ref local_var, ref pos) => (local_var, pos).to_viper(context, ast),
Expr::Variant(ref base, ref field, ref pos) => ast.field_access_with_pos(
@@ -763,7 +775,7 @@ impl<'v> ToViper<'v, viper::Expr<'v>> for Expr {
}
impl<'v, 'a, 'b> ToViper<'v, viper::Trigger<'v>> for (&'a Trigger, &'b Position) {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Trigger<'v> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Trigger<'v> {
ast.trigger_with_pos(
&self.0.elements().to_viper(context, ast)[..],
self.1.to_viper(context, ast),
@@ -772,7 +784,7 @@ impl<'v, 'a, 'b> ToViper<'v, viper::Trigger<'v>> for (&'a Trigger, &'b Position)
}
impl<'v, 'a, 'b> ToViper<'v, viper::Expr<'v>> for (&'a Const, &'b Position) {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Expr<'v> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Expr<'v> {
match self.0 {
Const::Bool(true) => ast.true_lit_with_pos(self.1.to_viper(context, ast)),
Const::Bool(false) => ast.false_lit_with_pos(self.1.to_viper(context, ast)),
@@ -808,7 +820,7 @@ impl<'v, 'a, 'b> ToViper<'v, viper::Expr<'v>> for (&'a Const, &'b Position) {
impl<'v> ToViper<'v, viper::Predicate<'v>> for Predicate {
#[tracing::instrument(name = "Predicate::to_viper", level = "debug", skip_all)]
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Predicate<'v> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Predicate<'v> {
match self {
Predicate::Struct(p) => p.to_viper(context, ast),
Predicate::Enum(p) => p.to_viper(context, ast),
@@ -825,7 +837,7 @@ impl<'v> ToViper<'v, viper::Predicate<'v>> for StructPredicate {
level = "trace",
skip(context, ast)
)]
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Predicate<'v> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Predicate<'v> {
ast.predicate(
&self.name,
&[self.this.to_viper_decl(context, ast)],
@@ -836,7 +848,7 @@ impl<'v> ToViper<'v, viper::Predicate<'v>> for StructPredicate {
impl<'v> ToViper<'v, viper::Predicate<'v>> for EnumPredicate {
#[tracing::instrument(name = "EnumPredicate::to_viper", level = "trace", skip(context, ast))]
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Predicate<'v> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Predicate<'v> {
ast.predicate(
&self.name,
&[self.this.to_viper_decl(context, ast)],
@@ -847,7 +859,7 @@ impl<'v> ToViper<'v, viper::Predicate<'v>> for EnumPredicate {
impl<'a, 'v> ToViper<'v, viper::Method<'v>> for &'a BodylessMethod {
#[tracing::instrument(name = "BodylessMethod::to_viper", level = "trace", skip(context, ast))]
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Method<'v> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Method<'v> {
ast.method(
&self.name,
&self.formal_args.to_viper_decl(context, ast),
@@ -861,7 +873,7 @@ impl<'a, 'v> ToViper<'v, viper::Method<'v>> for &'a BodylessMethod {
impl<'a, 'v> ToViper<'v, viper::Function<'v>> for &'a Function {
#[tracing::instrument(name = "Function::to_viper", level = "debug", skip_all)]
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Function<'v> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Function<'v> {
ast.function(
&self.get_identifier(),
&self.formal_args.to_viper_decl(context, ast),
@@ -876,7 +888,7 @@ impl<'a, 'v> ToViper<'v, viper::Function<'v>> for &'a Function {
impl<'a, 'v> ToViper<'v, viper::Domain<'v>> for &'a Domain {
#[tracing::instrument(name = "Domain::to_viper", level = "debug", skip_all)]
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Domain<'v> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Domain<'v> {
ast.domain(
&self.name,
&self.functions.to_viper(context, ast),
@@ -888,7 +900,7 @@ impl<'a, 'v> ToViper<'v, viper::Domain<'v>> for &'a Domain {
impl<'a, 'v> ToViper<'v, viper::DomainFunc<'v>> for &'a DomainFunc {
#[tracing::instrument(name = "DomainFunc::to_viper", level = "trace", skip(context, ast))]
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::DomainFunc<'v> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::DomainFunc<'v> {
ast.domain_func(
&self.get_identifier(),
&self.formal_args.to_viper_decl(context, ast),
@@ -901,7 +913,11 @@ impl<'a, 'v> ToViper<'v, viper::DomainFunc<'v>> for &'a DomainFunc {
impl<'a, 'v> ToViper<'v, viper::NamedDomainAxiom<'v>> for &'a DomainAxiom {
#[tracing::instrument(name = "DomainAxiom::to_viper", level = "trace", skip(context, ast))]
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::NamedDomainAxiom<'v> {
+ fn to_viper(
+ &self,
+ context: &mut Context<'v>,
+ ast: &AstFactory<'v>,
+ ) -> viper::NamedDomainAxiom<'v> {
if let Some(comment) = &self.comment {
ast.named_domain_axiom_with_comment(
&self.name,
@@ -920,7 +936,7 @@ impl<'a, 'v> ToViper<'v, viper::NamedDomainAxiom<'v>> for &'a DomainAxiom {
}
impl<'a, 'v> ToViper<'v, viper::Domain<'v>> for &'a BackendType {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Domain<'v> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Domain<'v> {
ast.backend_type(
&self.name,
&self.functions.to_viper(context, ast),
@@ -930,7 +946,7 @@ impl<'a, 'v> ToViper<'v, viper::Domain<'v>> for &'a BackendType {
}
impl<'a, 'v> ToViper<'v, viper::DomainFunc<'v>> for &'a BackendFuncDecl {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::DomainFunc<'v> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::DomainFunc<'v> {
ast.backend_func(
&self.get_identifier(),
&self.formal_args.to_viper_decl(context, ast),
@@ -944,13 +960,13 @@ impl<'a, 'v> ToViper<'v, viper::DomainFunc<'v>> for &'a BackendFuncDecl {
// Vectors
impl<'v> ToViper<'v, Vec>> for Vec {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> Vec> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> Vec> {
self.iter().map(|x| x.to_viper(context, ast)).collect()
}
}
impl<'v, 'a, 'b> ToViper<'v, Vec>> for (&'a Vec, &'b Position) {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> Vec> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> Vec> {
self.0
.iter()
.map(|x| (x, self.1).to_viper(context, ast))
@@ -959,7 +975,7 @@ impl<'v, 'a, 'b> ToViper<'v, Vec>> for (&'a Vec, &'b P
}
impl<'v, 'a, 'b> ToViper<'v, Vec>> for (&'a Vec, &'b Position) {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> Vec> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> Vec> {
self.0
.iter()
.map(|x| (x, self.1).to_viper(context, ast))
@@ -970,7 +986,7 @@ impl<'v, 'a, 'b> ToViper<'v, Vec>> for (&'a Vec, &'b
impl<'v> ToViperDecl<'v, Vec>> for Vec {
fn to_viper_decl(
&self,
- context: Context,
+ context: &mut Context<'v>,
ast: &AstFactory<'v>,
) -> Vec> {
self.iter().map(|x| x.to_viper_decl(context, ast)).collect()
@@ -978,62 +994,78 @@ impl<'v> ToViperDecl<'v, Vec>> for Vec {
}
impl<'v> ToViper<'v, Vec>> for Vec {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> Vec> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> Vec> {
self.iter().map(|x| x.to_viper(context, ast)).collect()
}
}
impl<'v> ToViper<'v, Vec>> for Vec {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> Vec> {
+ fn to_viper(
+ &self,
+ context: &mut Context<'v>,
+ ast: &AstFactory<'v>,
+ ) -> Vec> {
self.iter().map(|x| x.to_viper(context, ast)).collect()
}
}
impl<'v> ToViper<'v, Vec>> for Vec {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> Vec> {
+ fn to_viper(
+ &self,
+ context: &mut Context<'v>,
+ ast: &AstFactory<'v>,
+ ) -> Vec> {
self.iter().map(|x| x.to_viper(context, ast)).collect()
}
}
impl<'v> ToViper<'v, Vec>> for Vec {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> Vec> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> Vec> {
self.iter().map(|x| x.to_viper(context, ast)).collect()
}
}
impl<'v> ToViper<'v, Vec>> for Vec {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> Vec> {
+ fn to_viper(
+ &self,
+ context: &mut Context<'v>,
+ ast: &AstFactory<'v>,
+ ) -> Vec> {
self.iter().map(|x| x.to_viper(context, ast)).collect()
}
}
impl<'v> ToViper<'v, Vec>> for Vec {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> Vec> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> Vec> {
self.iter().map(|x| x.to_viper(context, ast)).collect()
}
}
impl<'v> ToViper<'v, Vec>> for Vec {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> Vec> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> Vec> {
self.iter().map(|x| x.to_viper(context, ast)).collect()
}
}
impl<'v> ToViper<'v, Vec>> for Vec {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> Vec> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> Vec> {
self.iter().map(|x| x.to_viper(context, ast)).collect()
}
}
impl<'v> ToViper<'v, Vec>> for Vec {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> Vec> {
+ fn to_viper(
+ &self,
+ context: &mut Context<'v>,
+ ast: &AstFactory<'v>,
+ ) -> Vec> {
self.iter().map(|x| x.to_viper(context, ast)).collect()
}
}
impl<'a, 'v> ToViper<'v, viper::Method<'v>> for &'a CfgMethod {
#[tracing::instrument(name = "CfgMethod::to_viper", level = "debug", skip_all)]
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> viper::Method<'v> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> viper::Method<'v> {
let mut blocks_ast: Vec = vec![];
let mut declarations: Vec = vec![];
@@ -1100,8 +1132,8 @@ impl<'a, 'v> ToViper<'v, viper::Method<'v>> for &'a CfgMethod {
fn cfg_method_convert_basic_block_path<'v>(
cfg_method: &CfgMethod,
mut path: Vec,
- context: Context,
- ast: &'v AstFactory,
+ context: &mut Context<'v>,
+ ast: &AstFactory<'v>,
blocks_ast: &mut Vec>,
declarations: &mut Vec>,
) {
@@ -1189,7 +1221,7 @@ fn cfg_method_convert_basic_block_path<'v>(
}
impl<'v> ToViper<'v, Vec>> for Vec {
- fn to_viper(&self, context: Context, ast: &AstFactory<'v>) -> Vec> {
+ fn to_viper(&self, context: &mut Context<'v>, ast: &AstFactory<'v>) -> Vec> {
self.iter().map(|x| x.to_viper(context, ast)).collect()
}
}
@@ -1198,13 +1230,13 @@ fn index_to_label(basic_block_labels: &[String], index: usize) -> String {
basic_block_labels[index].clone()
}
-fn successor_to_viper<'a>(
- context: Context,
- ast: &'a AstFactory,
+fn successor_to_viper<'v>(
+ context: &mut Context<'v>,
+ ast: &AstFactory<'v>,
index: usize,
basic_block_labels: &[String],
successor: &Successor,
-) -> viper::Stmt<'a> {
+) -> viper::Stmt<'v> {
match *successor {
Successor::Undefined => panic!(
"CFG block '{}' has no successor.",
@@ -1213,7 +1245,7 @@ fn successor_to_viper<'a>(
Successor::Return => ast.goto(RETURN_LABEL),
Successor::Goto(target) => ast.goto(&basic_block_labels[target.index()]),
Successor::GotoSwitch(ref successors, ref default_target) => {
- let mut stmts: Vec> = vec![];
+ let mut stmts: Vec> = vec![];
for (test, target) in successors {
let goto = ast.seqn(&[ast.goto(&basic_block_labels[target.index()])], &[]);
let skip = ast.seqn(&[], &[]);
@@ -1227,13 +1259,13 @@ fn successor_to_viper<'a>(
}
}
-fn block_to_viper<'a>(
- context: Context,
- ast: &'a AstFactory,
+fn block_to_viper<'v>(
+ context: &mut Context<'v>,
+ ast: &AstFactory<'v>,
basic_block_labels: &[String],
block: &CfgBlock,
index: usize,
-) -> viper::Stmt<'a> {
+) -> viper::Stmt<'v> {
let label = &basic_block_labels[index];
let mut stmts: Vec = vec![
// To put a bit of white space between blocks.
@@ -1288,7 +1320,7 @@ fn unsigned_max_for_size(size: BitVectorSize) -> u128 {
}
fn unsigned_bv_to_signed_int<'v>(
- context: Context,
+ context: &mut Context<'v>,
ast: &AstFactory<'v>,
size: BitVectorSize,
value: &Expr,
diff --git a/prusti-contracts/prusti-contracts-proc-macros/src/lib.rs b/prusti-contracts/prusti-contracts-proc-macros/src/lib.rs
index 9a50a2f3f8c..59b8fbdfd0f 100644
--- a/prusti-contracts/prusti-contracts-proc-macros/src/lib.rs
+++ b/prusti-contracts/prusti-contracts-proc-macros/src/lib.rs
@@ -10,18 +10,68 @@ pub fn requires(_attr: TokenStream, tokens: TokenStream) -> TokenStream {
tokens
}
+#[cfg(not(feature = "prusti"))]
+#[proc_macro_attribute]
+pub fn structural_requires(_attr: TokenStream, tokens: TokenStream) -> TokenStream {
+ tokens
+}
+
+/// FIXME: Remove
+#[cfg(not(feature = "prusti"))]
+#[proc_macro_attribute]
+pub fn not_require(_attr: TokenStream, tokens: TokenStream) -> TokenStream {
+ tokens
+}
+
#[cfg(not(feature = "prusti"))]
#[proc_macro_attribute]
pub fn invariant(_attr: TokenStream, tokens: TokenStream) -> TokenStream {
tokens
}
+#[cfg(not(feature = "prusti"))]
+#[proc_macro_attribute]
+pub fn structural_invariant(_attr: TokenStream, tokens: TokenStream) -> TokenStream {
+ tokens
+}
+
+#[cfg(not(feature = "prusti"))]
+#[proc_macro_attribute]
+pub fn broken_invariant(_attr: TokenStream, tokens: TokenStream) -> TokenStream {
+ tokens
+}
+
#[cfg(not(feature = "prusti"))]
#[proc_macro_attribute]
pub fn ensures(_attr: TokenStream, tokens: TokenStream) -> TokenStream {
tokens
}
+#[cfg(not(feature = "prusti"))]
+#[proc_macro_attribute]
+pub fn panic_ensures(_attr: TokenStream, tokens: TokenStream) -> TokenStream {
+ tokens
+}
+
+#[cfg(not(feature = "prusti"))]
+#[proc_macro_attribute]
+pub fn structural_panic_ensures(_attr: TokenStream, tokens: TokenStream) -> TokenStream {
+ tokens
+}
+
+#[cfg(not(feature = "prusti"))]
+#[proc_macro_attribute]
+pub fn structural_ensures(_attr: TokenStream, tokens: TokenStream) -> TokenStream {
+ tokens
+}
+
+/// FIXME: Remove
+#[cfg(not(feature = "prusti"))]
+#[proc_macro_attribute]
+pub fn not_ensure(_attr: TokenStream, tokens: TokenStream) -> TokenStream {
+ tokens
+}
+
#[cfg(not(feature = "prusti"))]
#[proc_macro_attribute]
pub fn after_expiry(_attr: TokenStream, tokens: TokenStream) -> TokenStream {
@@ -52,18 +102,48 @@ pub fn verified(_attr: TokenStream, tokens: TokenStream) -> TokenStream {
tokens
}
+#[cfg(not(feature = "prusti"))]
+#[proc_macro_attribute]
+pub fn non_verified_pure(_attr: TokenStream, tokens: TokenStream) -> TokenStream {
+ tokens
+}
+
+#[cfg(not(feature = "prusti"))]
+#[proc_macro_attribute]
+pub fn no_panic(_attr: TokenStream, tokens: TokenStream) -> TokenStream {
+ tokens
+}
+
+#[cfg(not(feature = "prusti"))]
+#[proc_macro_attribute]
+pub fn no_panic_ensures_postcondition(_attr: TokenStream, tokens: TokenStream) -> TokenStream {
+ tokens
+}
+
#[cfg(not(feature = "prusti"))]
#[proc_macro]
pub fn body_invariant(_tokens: TokenStream) -> TokenStream {
TokenStream::new()
}
+#[cfg(not(feature = "prusti"))]
+#[proc_macro]
+pub fn structural_body_invariant(_tokens: TokenStream) -> TokenStream {
+ TokenStream::new()
+}
+
#[cfg(not(feature = "prusti"))]
#[proc_macro]
pub fn prusti_assert(_tokens: TokenStream) -> TokenStream {
TokenStream::new()
}
+#[cfg(not(feature = "prusti"))]
+#[proc_macro]
+pub fn prusti_structural_assert(_tokens: TokenStream) -> TokenStream {
+ TokenStream::new()
+}
+
#[cfg(not(feature = "prusti"))]
#[proc_macro]
pub fn prusti_assume(_tokens: TokenStream) -> TokenStream {
@@ -76,6 +156,36 @@ pub fn prusti_refute(_tokens: TokenStream) -> TokenStream {
TokenStream::new()
}
+#[cfg(not(feature = "prusti"))]
+#[proc_macro]
+pub fn prusti_structural_assume(_tokens: TokenStream) -> TokenStream {
+ TokenStream::new()
+}
+
+#[cfg(not(feature = "prusti"))]
+#[proc_macro]
+pub fn prusti_split_on(_tokens: TokenStream) -> TokenStream {
+ TokenStream::new()
+}
+
+#[cfg(not(feature = "prusti"))]
+#[proc_macro]
+pub fn materialize_predicate(_tokens: TokenStream) -> TokenStream {
+ TokenStream::new()
+}
+
+#[cfg(not(feature = "prusti"))]
+#[proc_macro]
+pub fn quantified_predicate(_tokens: TokenStream) -> TokenStream {
+ TokenStream::new()
+}
+
+#[cfg(not(feature = "prusti"))]
+#[proc_macro]
+pub fn assume_allocation_never_fails(_tokens: TokenStream) -> TokenStream {
+ TokenStream::new()
+}
+
#[cfg(not(feature = "prusti"))]
#[proc_macro_attribute]
pub fn refine_trait_spec(_attr: TokenStream, tokens: TokenStream) -> TokenStream {
@@ -113,164 +223,738 @@ pub fn ghost(_tokens: TokenStream) -> TokenStream {
}
#[cfg(not(feature = "prusti"))]
-#[proc_macro_attribute]
-pub fn print_counterexample(_attr: TokenStream, tokens: TokenStream) -> TokenStream {
- tokens
+#[proc_macro]
+pub fn on_drop_unwind(_tokens: TokenStream) -> TokenStream {
+ TokenStream::new()
}
#[cfg(not(feature = "prusti"))]
-#[proc_macro_attribute]
-pub fn terminates(_attr: TokenStream, _tokens: TokenStream) -> TokenStream {
+#[proc_macro]
+pub fn before_drop(_tokens: TokenStream) -> TokenStream {
TokenStream::new()
}
#[cfg(not(feature = "prusti"))]
#[proc_macro]
-pub fn body_variant(_tokens: TokenStream) -> TokenStream {
+pub fn after_drop(_tokens: TokenStream) -> TokenStream {
TokenStream::new()
}
-// ----------------------
-// --- PRUSTI ENABLED ---
+#[cfg(not(feature = "prusti"))]
+#[proc_macro]
+pub fn with_finally(_tokens: TokenStream) -> TokenStream {
+ TokenStream::new()
+}
-#[cfg(feature = "prusti")]
-use prusti_specs::{rewrite_prusti_attributes, SpecAttributeKind};
+#[cfg(not(feature = "prusti"))]
+#[proc_macro]
+pub fn checked(_tokens: TokenStream) -> TokenStream {
+ TokenStream::new()
+}
-#[cfg(feature = "prusti")]
-#[proc_macro_attribute]
-pub fn requires(attr: TokenStream, tokens: TokenStream) -> TokenStream {
- rewrite_prusti_attributes(SpecAttributeKind::Requires, attr.into(), tokens.into()).into()
+#[cfg(not(feature = "prusti"))]
+#[proc_macro]
+pub fn checked(_tokens: TokenStream) -> TokenStream {
+ TokenStream::new()
}
-#[cfg(feature = "prusti")]
+#[cfg(not(feature = "prusti"))]
#[proc_macro_attribute]
-pub fn ensures(attr: TokenStream, tokens: TokenStream) -> TokenStream {
- rewrite_prusti_attributes(SpecAttributeKind::Ensures, attr.into(), tokens.into()).into()
+pub fn print_counterexample(_attr: TokenStream, tokens: TokenStream) -> TokenStream {
+ tokens
}
-#[cfg(feature = "prusti")]
+#[cfg(not(feature = "prusti"))]
#[proc_macro_attribute]
-pub fn after_expiry(attr: TokenStream, tokens: TokenStream) -> TokenStream {
- rewrite_prusti_attributes(SpecAttributeKind::AfterExpiry, attr.into(), tokens.into()).into()
+pub fn terminates(_attr: TokenStream, _tokens: TokenStream) -> TokenStream {
+ TokenStream::new()
}
-#[cfg(feature = "prusti")]
-#[proc_macro_attribute]
-pub fn assert_on_expiry(attr: TokenStream, tokens: TokenStream) -> TokenStream {
- rewrite_prusti_attributes(
- SpecAttributeKind::AssertOnExpiry,
- attr.into(),
- tokens.into(),
- )
- .into()
+#[cfg(not(feature = "prusti"))]
+#[proc_macro]
+pub fn body_variant(_tokens: TokenStream) -> TokenStream {
+ TokenStream::new()
}
-#[cfg(feature = "prusti")]
-#[proc_macro_attribute]
-pub fn pure(attr: TokenStream, tokens: TokenStream) -> TokenStream {
- rewrite_prusti_attributes(SpecAttributeKind::Pure, attr.into(), tokens.into()).into()
+#[cfg(not(feature = "prusti"))]
+#[proc_macro]
+pub fn manually_manage(_tokens: TokenStream) -> TokenStream {
+ TokenStream::new()
}
-#[cfg(feature = "prusti")]
-#[proc_macro_attribute]
-pub fn trusted(attr: TokenStream, tokens: TokenStream) -> TokenStream {
- prusti_specs::trusted(attr.into(), tokens.into()).into()
+#[cfg(not(feature = "prusti"))]
+#[proc_macro]
+pub fn pack(_tokens: TokenStream) -> TokenStream {
+ TokenStream::new()
}
-#[cfg(feature = "prusti")]
-#[proc_macro_attribute]
-pub fn verified(attr: TokenStream, tokens: TokenStream) -> TokenStream {
- rewrite_prusti_attributes(SpecAttributeKind::Verified, attr.into(), tokens.into()).into()
+#[cfg(not(feature = "prusti"))]
+#[proc_macro]
+pub fn unpack(_tokens: TokenStream) -> TokenStream {
+ TokenStream::new()
}
-#[cfg(feature = "prusti")]
+#[cfg(not(feature = "prusti"))]
#[proc_macro]
-pub fn body_invariant(tokens: TokenStream) -> TokenStream {
- prusti_specs::body_invariant(tokens.into()).into()
+pub fn obtain(_tokens: TokenStream) -> TokenStream {
+ TokenStream::new()
}
-#[cfg(feature = "prusti")]
+#[cfg(not(feature = "prusti"))]
#[proc_macro]
-pub fn prusti_assert(tokens: TokenStream) -> TokenStream {
- prusti_specs::prusti_assertion(tokens.into()).into()
+pub fn pack_ref(_tokens: TokenStream) -> TokenStream {
+ TokenStream::new()
}
-#[cfg(feature = "prusti")]
+#[cfg(not(feature = "prusti"))]
#[proc_macro]
-pub fn prusti_assume(tokens: TokenStream) -> TokenStream {
- prusti_specs::prusti_assume(tokens.into()).into()
+pub fn unpack_ref(_tokens: TokenStream) -> TokenStream {
+ TokenStream::new()
}
-#[cfg(feature = "prusti")]
+#[cfg(not(feature = "prusti"))]
#[proc_macro]
-pub fn prusti_refute(tokens: TokenStream) -> TokenStream {
- prusti_specs::prusti_refutation(tokens.into()).into()
+pub fn pack_mut_ref(_tokens: TokenStream) -> TokenStream {
+ TokenStream::new()
}
-#[cfg(feature = "prusti")]
+#[cfg(not(feature = "prusti"))]
#[proc_macro]
-pub fn closure(tokens: TokenStream) -> TokenStream {
- prusti_specs::closure(tokens.into()).into()
+pub fn unpack_mut_ref(_tokens: TokenStream) -> TokenStream {
+ TokenStream::new()
}
-#[cfg(feature = "prusti")]
-#[proc_macro_attribute]
-pub fn refine_trait_spec(attr: TokenStream, tokens: TokenStream) -> TokenStream {
- prusti_specs::refine_trait_spec(attr.into(), tokens.into()).into()
+#[cfg(not(feature = "prusti"))]
+#[proc_macro]
+pub fn pack_mut_ref_obligation(_tokens: TokenStream) -> TokenStream {
+ TokenStream::new()
}
-#[cfg(feature = "prusti")]
-#[proc_macro_attribute]
-pub fn extern_spec(attr: TokenStream, tokens: TokenStream) -> TokenStream {
- prusti_specs::extern_spec(attr.into(), tokens.into()).into()
+#[cfg(not(feature = "prusti"))]
+#[proc_macro]
+pub fn unpack_mut_ref_obligation(_tokens: TokenStream) -> TokenStream {
+ TokenStream::new()
}
-#[cfg(feature = "prusti")]
-#[proc_macro_attribute]
-pub fn invariant(attr: TokenStream, tokens: TokenStream) -> TokenStream {
- prusti_specs::invariant(attr.into(), tokens.into()).into()
+#[cfg(not(feature = "prusti"))]
+#[proc_macro]
+pub fn take_lifetime(_tokens: TokenStream) -> TokenStream {
+ TokenStream::new()
}
-#[cfg(feature = "prusti")]
+#[cfg(not(feature = "prusti"))]
#[proc_macro]
-pub fn predicate(tokens: TokenStream) -> TokenStream {
- prusti_specs::predicate(tokens.into()).into()
+pub fn end_loan(_tokens: TokenStream) -> TokenStream {
+ TokenStream::new()
}
-#[cfg(feature = "prusti")]
-#[proc_macro_attribute]
-pub fn model(_attr: TokenStream, tokens: TokenStream) -> TokenStream {
- prusti_specs::type_model(_attr.into(), tokens.into()).into()
+#[cfg(not(feature = "prusti"))]
+#[proc_macro]
+pub fn set_lifetime_for_raw_pointer_reference_casts(_tokens: TokenStream) -> TokenStream {
+ TokenStream::new()
}
-#[cfg(feature = "prusti")]
-#[proc_macro_attribute]
-pub fn refine_spec(attr: TokenStream, tokens: TokenStream) -> TokenStream {
- rewrite_prusti_attributes(SpecAttributeKind::RefineSpec, attr.into(), tokens.into()).into()
+#[cfg(not(feature = "prusti"))]
+#[proc_macro]
+pub fn attach_drop_lifetime(_tokens: TokenStream) -> TokenStream {
+ TokenStream::new()
}
-#[cfg(feature = "prusti")]
+#[cfg(not(feature = "prusti"))]
#[proc_macro]
-pub fn ghost(tokens: TokenStream) -> TokenStream {
- prusti_specs::ghost(tokens.into()).into()
+pub fn join(_tokens: TokenStream) -> TokenStream {
+ TokenStream::new()
}
-#[cfg(feature = "prusti")]
-#[proc_macro_attribute]
-pub fn print_counterexample(attr: TokenStream, tokens: TokenStream) -> TokenStream {
- prusti_specs::print_counterexample(attr.into(), tokens.into()).into()
+#[cfg(not(feature = "prusti"))]
+#[proc_macro]
+pub fn join_range(_tokens: TokenStream) -> TokenStream {
+ TokenStream::new()
}
-#[cfg(feature = "prusti")]
-#[proc_macro_attribute]
-pub fn terminates(attr: TokenStream, tokens: TokenStream) -> TokenStream {
- rewrite_prusti_attributes(SpecAttributeKind::Terminates, attr.into(), tokens.into()).into()
+#[cfg(not(feature = "prusti"))]
+#[proc_macro]
+pub fn split(_tokens: TokenStream) -> TokenStream {
+ TokenStream::new()
}
-#[cfg(feature = "prusti")]
+#[cfg(not(feature = "prusti"))]
#[proc_macro]
-pub fn body_variant(tokens: TokenStream) -> TokenStream {
- prusti_specs::body_variant(tokens.into()).into()
+pub fn split_range(_tokens: TokenStream) -> TokenStream {
+ TokenStream::new()
+}
+
+#[cfg(not(feature = "prusti"))]
+#[proc_macro]
+pub fn stash_range(_tokens: TokenStream) -> TokenStream {
+ TokenStream::new()
+}
+
+#[cfg(not(feature = "prusti"))]
+#[proc_macro]
+pub fn restore_stash_range(_tokens: TokenStream) -> TokenStream {
+ TokenStream::new()
+}
+
+#[cfg(not(feature = "prusti"))]
+#[proc_macro]
+pub fn close_ref(_tokens: TokenStream) -> TokenStream {
+ TokenStream::new()
+}
+
+#[cfg(not(feature = "prusti"))]
+#[proc_macro]
+pub fn open_ref(_tokens: TokenStream) -> TokenStream {
+ TokenStream::new()
+}
+
+#[cfg(not(feature = "prusti"))]
+#[proc_macro]
+pub fn close_mut_ref(_tokens: TokenStream) -> TokenStream {
+ TokenStream::new()
+}
+
+#[cfg(not(feature = "prusti"))]
+#[proc_macro]
+pub fn open_mut_ref(_tokens: TokenStream) -> TokenStream {
+ TokenStream::new()
+}
+
+#[cfg(not(feature = "prusti"))]
+#[proc_macro]
+pub fn restore_mut_borrowed(_tokens: TokenStream) -> TokenStream {
+ TokenStream::new()
+}
+
+#[cfg(not(feature = "prusti"))]
+#[proc_macro]
+pub fn resolve(_tokens: TokenStream) -> TokenStream {
+ TokenStream::new()
+}
+
+#[cfg(not(feature = "prusti"))]
+#[proc_macro]
+pub fn resolve_range(_tokens: TokenStream) -> TokenStream {
+ TokenStream::new()
+}
+
+#[cfg(not(feature = "prusti"))]
+#[proc_macro]
+pub fn forget_initialization(_tokens: TokenStream) -> TokenStream {
+ TokenStream::new()
+}
+
+#[cfg(not(feature = "prusti"))]
+#[proc_macro]
+pub fn forget_initialization_range(_tokens: TokenStream) -> TokenStream {
+ TokenStream::new()
+}
+
+#[cfg(not(feature = "prusti"))]
+#[proc_macro]
+pub fn restore(_tokens: TokenStream) -> TokenStream {
+ TokenStream::new()
+}
+
+#[cfg(not(feature = "prusti"))]
+#[proc_macro]
+pub fn set_union_active_field(_tokens: TokenStream) -> TokenStream {
+ TokenStream::new()
+}
+
+// ----------------------
+// --- PRUSTI ENABLED ---
+
+#[cfg(feature = "prusti")]
+use prusti_specs::{rewrite_prusti_attributes, SpecAttributeKind};
+
+#[cfg(feature = "prusti")]
+#[proc_macro_attribute]
+pub fn requires(attr: TokenStream, tokens: TokenStream) -> TokenStream {
+ rewrite_prusti_attributes(SpecAttributeKind::Requires, attr.into(), tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro_attribute]
+pub fn structural_requires(attr: TokenStream, tokens: TokenStream) -> TokenStream {
+ rewrite_prusti_attributes(
+ SpecAttributeKind::StructuralRequires,
+ attr.into(),
+ tokens.into(),
+ )
+ .into()
+}
+
+/// FIXME: Remove.
+#[cfg(feature = "prusti")]
+#[proc_macro_attribute]
+pub fn not_require(attr: TokenStream, tokens: TokenStream) -> TokenStream {
+ rewrite_prusti_attributes(SpecAttributeKind::NotRequire, attr.into(), tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro_attribute]
+pub fn ensures(attr: TokenStream, tokens: TokenStream) -> TokenStream {
+ rewrite_prusti_attributes(SpecAttributeKind::Ensures, attr.into(), tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro_attribute]
+pub fn panic_ensures(attr: TokenStream, tokens: TokenStream) -> TokenStream {
+ rewrite_prusti_attributes(SpecAttributeKind::PanicEnsures, attr.into(), tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro_attribute]
+pub fn structural_ensures(attr: TokenStream, tokens: TokenStream) -> TokenStream {
+ rewrite_prusti_attributes(
+ SpecAttributeKind::StructuralEnsures,
+ attr.into(),
+ tokens.into(),
+ )
+ .into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro_attribute]
+pub fn structural_panic_ensures(attr: TokenStream, tokens: TokenStream) -> TokenStream {
+ rewrite_prusti_attributes(
+ SpecAttributeKind::StructuralPanicEnsures,
+ attr.into(),
+ tokens.into(),
+ )
+ .into()
+}
+
+/// FIXME: Remove.
+#[cfg(feature = "prusti")]
+#[proc_macro_attribute]
+pub fn not_ensure(attr: TokenStream, tokens: TokenStream) -> TokenStream {
+ rewrite_prusti_attributes(SpecAttributeKind::NotEnsure, attr.into(), tokens.into()).into()
+}
+
+/// FIXME: Cleanup.
+#[cfg(feature = "prusti")]
+#[proc_macro_attribute]
+pub fn broken_invariant(attr: TokenStream, tokens: TokenStream) -> TokenStream {
+ rewrite_prusti_attributes(SpecAttributeKind::NotRequire, attr.into(), tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro_attribute]
+pub fn after_expiry(attr: TokenStream, tokens: TokenStream) -> TokenStream {
+ rewrite_prusti_attributes(SpecAttributeKind::AfterExpiry, attr.into(), tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro_attribute]
+pub fn assert_on_expiry(attr: TokenStream, tokens: TokenStream) -> TokenStream {
+ rewrite_prusti_attributes(
+ SpecAttributeKind::AssertOnExpiry,
+ attr.into(),
+ tokens.into(),
+ )
+ .into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro_attribute]
+pub fn pure(attr: TokenStream, tokens: TokenStream) -> TokenStream {
+ rewrite_prusti_attributes(SpecAttributeKind::Pure, attr.into(), tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro_attribute]
+pub fn trusted(attr: TokenStream, tokens: TokenStream) -> TokenStream {
+ prusti_specs::trusted(attr.into(), tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro_attribute]
+pub fn verified(attr: TokenStream, tokens: TokenStream) -> TokenStream {
+ rewrite_prusti_attributes(SpecAttributeKind::Verified, attr.into(), tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro_attribute]
+pub fn non_verified_pure(attr: TokenStream, tokens: TokenStream) -> TokenStream {
+ rewrite_prusti_attributes(
+ SpecAttributeKind::NonVerifiedPure,
+ attr.into(),
+ tokens.into(),
+ )
+ .into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro_attribute]
+pub fn no_panic(attr: TokenStream, tokens: TokenStream) -> TokenStream {
+ rewrite_prusti_attributes(SpecAttributeKind::NoPanic, attr.into(), tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro_attribute]
+pub fn no_panic_ensures_postcondition(attr: TokenStream, tokens: TokenStream) -> TokenStream {
+ rewrite_prusti_attributes(
+ SpecAttributeKind::NoPanicEnsuresPostcondition,
+ attr.into(),
+ tokens.into(),
+ )
+ .into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn body_invariant(tokens: TokenStream) -> TokenStream {
+ prusti_specs::body_invariant(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn structural_body_invariant(tokens: TokenStream) -> TokenStream {
+ prusti_specs::structural_body_invariant(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn prusti_assert(tokens: TokenStream) -> TokenStream {
+ prusti_specs::prusti_assertion(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn prusti_structural_assert(tokens: TokenStream) -> TokenStream {
+ prusti_specs::prusti_structural_assert(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn prusti_assume(tokens: TokenStream) -> TokenStream {
+ prusti_specs::prusti_assume(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn prusti_refute(tokens: TokenStream) -> TokenStream {
+ prusti_specs::prusti_refutation(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn prusti_structural_assume(tokens: TokenStream) -> TokenStream {
+ prusti_specs::prusti_structural_assume(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn prusti_split_on(tokens: TokenStream) -> TokenStream {
+ prusti_specs::prusti_split_on(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn materialize_predicate(tokens: TokenStream) -> TokenStream {
+ prusti_specs::materialize_predicate(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn quantified_predicate(tokens: TokenStream) -> TokenStream {
+ prusti_specs::quantified_predicate(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn assume_allocation_never_fails(tokens: TokenStream) -> TokenStream {
+ prusti_specs::assume_allocation_never_fails(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn closure(tokens: TokenStream) -> TokenStream {
+ prusti_specs::closure(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro_attribute]
+pub fn refine_trait_spec(attr: TokenStream, tokens: TokenStream) -> TokenStream {
+ prusti_specs::refine_trait_spec(attr.into(), tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro_attribute]
+pub fn extern_spec(attr: TokenStream, tokens: TokenStream) -> TokenStream {
+ prusti_specs::extern_spec(attr.into(), tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro_attribute]
+pub fn invariant(attr: TokenStream, tokens: TokenStream) -> TokenStream {
+ prusti_specs::invariant(attr.into(), tokens.into(), false).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro_attribute]
+pub fn structural_invariant(attr: TokenStream, tokens: TokenStream) -> TokenStream {
+ prusti_specs::invariant(attr.into(), tokens.into(), true).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn predicate(tokens: TokenStream) -> TokenStream {
+ prusti_specs::predicate(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro_attribute]
+pub fn model(_attr: TokenStream, tokens: TokenStream) -> TokenStream {
+ prusti_specs::type_model(_attr.into(), tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro_attribute]
+pub fn refine_spec(attr: TokenStream, tokens: TokenStream) -> TokenStream {
+ rewrite_prusti_attributes(SpecAttributeKind::RefineSpec, attr.into(), tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn ghost(tokens: TokenStream) -> TokenStream {
+ prusti_specs::ghost(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn on_drop_unwind(tokens: TokenStream) -> TokenStream {
+ prusti_specs::on_drop_unwind(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn before_drop(tokens: TokenStream) -> TokenStream {
+ prusti_specs::before_drop(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn after_drop(tokens: TokenStream) -> TokenStream {
+ prusti_specs::after_drop(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn with_finally(tokens: TokenStream) -> TokenStream {
+ prusti_specs::with_finally(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn checked(tokens: TokenStream) -> TokenStream {
+ prusti_specs::checked(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro_attribute]
+pub fn print_counterexample(attr: TokenStream, tokens: TokenStream) -> TokenStream {
+ prusti_specs::print_counterexample(attr.into(), tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro_attribute]
+pub fn terminates(attr: TokenStream, tokens: TokenStream) -> TokenStream {
+ rewrite_prusti_attributes(SpecAttributeKind::Terminates, attr.into(), tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn body_variant(tokens: TokenStream) -> TokenStream {
+ prusti_specs::body_variant(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn manually_manage(tokens: TokenStream) -> TokenStream {
+ prusti_specs::manually_manage(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn pack(tokens: TokenStream) -> TokenStream {
+ prusti_specs::pack(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn unpack(tokens: TokenStream) -> TokenStream {
+ prusti_specs::unpack(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn obtain(tokens: TokenStream) -> TokenStream {
+ prusti_specs::obtain(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn pack_ref(tokens: TokenStream) -> TokenStream {
+ prusti_specs::pack_ref(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn unpack_ref(tokens: TokenStream) -> TokenStream {
+ prusti_specs::unpack_ref(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn pack_mut_ref(tokens: TokenStream) -> TokenStream {
+ prusti_specs::pack_mut_ref(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn unpack_mut_ref(tokens: TokenStream) -> TokenStream {
+ prusti_specs::unpack_mut_ref(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn pack_mut_ref_obligation(tokens: TokenStream) -> TokenStream {
+ prusti_specs::pack_mut_ref_obligation(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn unpack_mut_ref_obligation(tokens: TokenStream) -> TokenStream {
+ prusti_specs::unpack_mut_ref_obligation(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn take_lifetime(tokens: TokenStream) -> TokenStream {
+ prusti_specs::take_lifetime(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn end_loan(tokens: TokenStream) -> TokenStream {
+ prusti_specs::end_loan(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn set_lifetime_for_raw_pointer_reference_casts(tokens: TokenStream) -> TokenStream {
+ prusti_specs::set_lifetime_for_raw_pointer_reference_casts(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn attach_drop_lifetime(tokens: TokenStream) -> TokenStream {
+ prusti_specs::attach_drop_lifetime(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn join(tokens: TokenStream) -> TokenStream {
+ prusti_specs::join(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn join_range(tokens: TokenStream) -> TokenStream {
+ prusti_specs::join_range(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn split(tokens: TokenStream) -> TokenStream {
+ prusti_specs::split(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn split_range(tokens: TokenStream) -> TokenStream {
+ prusti_specs::split_range(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn stash_range(tokens: TokenStream) -> TokenStream {
+ prusti_specs::stash_range(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn restore_stash_range(tokens: TokenStream) -> TokenStream {
+ prusti_specs::restore_stash_range(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn close_ref(tokens: TokenStream) -> TokenStream {
+ prusti_specs::close_ref(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn open_ref(tokens: TokenStream) -> TokenStream {
+ prusti_specs::open_ref(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn close_mut_ref(tokens: TokenStream) -> TokenStream {
+ prusti_specs::close_mut_ref(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn open_mut_ref(tokens: TokenStream) -> TokenStream {
+ prusti_specs::open_mut_ref(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn restore_mut_borrowed(tokens: TokenStream) -> TokenStream {
+ prusti_specs::restore_mut_borrowed(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn resolve(tokens: TokenStream) -> TokenStream {
+ prusti_specs::resolve(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn resolve_range(tokens: TokenStream) -> TokenStream {
+ prusti_specs::resolve_range(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn forget_initialization(tokens: TokenStream) -> TokenStream {
+ prusti_specs::forget_initialization(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn forget_initialization_range(tokens: TokenStream) -> TokenStream {
+ prusti_specs::forget_initialization_range(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn restore(tokens: TokenStream) -> TokenStream {
+ prusti_specs::restore(tokens.into()).into()
+}
+
+#[cfg(feature = "prusti")]
+#[proc_macro]
+pub fn set_union_active_field(tokens: TokenStream) -> TokenStream {
+ prusti_specs::set_union_active_field(tokens.into()).into()
}
// Ensure that you've also crated a transparent `#[cfg(not(feature = "prusti"))]`
diff --git a/prusti-contracts/prusti-contracts/src/core_spec.rs b/prusti-contracts/prusti-contracts/src/core_spec.rs
index 61fa73e42b8..a8165b62649 100644
--- a/prusti-contracts/prusti-contracts/src/core_spec.rs
+++ b/prusti-contracts/prusti-contracts/src/core_spec.rs
@@ -4,15 +4,349 @@ use crate::*;
impl ::core::result::Result {
#[pure]
#[ensures(result == matches!(self, Ok(_)))]
+ #[no_panic]
+ #[no_panic_ensures_postcondition]
fn is_ok(&self) -> bool;
#[pure]
#[ensures(result == matches!(self, Err(_)))]
+ #[no_panic]
+ #[no_panic_ensures_postcondition]
fn is_err(&self) -> bool;
}
#[extern_spec]
impl ::core::result::Result {
#[requires(matches!(self, Ok(_)))]
+ #[ensures(match self {
+ Ok(value) => result === value,
+ Err(_) => false,
+ })]
+ #[no_panic_ensures_postcondition]
fn unwrap(self) -> T;
}
+
+#[extern_spec]
+impl ::core::option::Option {
+ #[requires(matches!(self, Some(_)))]
+ #[ensures(match self {
+ Some(value) => result === value,
+ None => false,
+ })]
+ #[no_panic_ensures_postcondition]
+ fn unwrap(self) -> T;
+}
+
+// Crashes ☹
+type Pointer = *const T;
+#[extern_spec]
+impl Pointer {
+ #[trusted]
+ #[terminates]
+ #[pure]
+ // FIXME: This is needed because this function is special cased only in the
+ // pure encoder and not in the impure one.
+ #[ensures(result == self.is_null())]
+ #[no_panic]
+ #[no_panic_ensures_postcondition]
+ fn is_null(self) -> bool;
+
+ #[trusted]
+ #[terminates]
+ #[pure]
+ // FIXME: Check provenance.
+ #[structural_requires(Int::new_isize(count) * Int::new_usize(std::mem::size_of::()) <= Int::new_isize(isize::MAX))]
+ #[ensures(result == address_offset(self, Int::new_isize(count)))]
+ #[no_panic]
+ #[no_panic_ensures_postcondition]
+ unsafe fn offset(self, count: isize) -> *const T;
+
+ #[trusted]
+ #[terminates]
+ #[pure]
+ // FIXME: Properly specify the wrapping arithmetic.
+ #[ensures(result == address_offset(self, Int::new_isize(count)))]
+ #[no_panic]
+ #[no_panic_ensures_postcondition]
+ fn wrapping_offset(self, count: isize) -> *const T;
+
+ #[trusted]
+ #[terminates]
+ #[pure]
+ // FIXME: Check provenance.
+ #[structural_requires(same_allocation(self, origin))]
+ // #[structural_requires(address_from(self, origin) * Int::new_usize(std::mem::size_of::()) <= Int::new_isize(isize::MAX))]
+ #[structural_requires(multiply_int(address_from(self, origin), Int::new_usize(std::mem::size_of::())) <= Int::new_isize(isize::MAX))]
+ #[structural_requires(address_from(self, origin) >= Int::new_isize(0))]
+ #[ensures(Int::new_isize(result) == address_from(self, origin))]
+ #[no_panic]
+ #[no_panic_ensures_postcondition]
+ unsafe fn offset_from(self, origin: *const T) -> isize;
+
+ #[trusted]
+ #[terminates]
+ #[pure]
+ // FIXME: Check provenance.
+ // #[structural_requires(Int::new_usize(count) * Int::new_usize(std::mem::size_of::()) <= Int::new_isize(isize::MAX))]
+ #[structural_requires(multiply_int(Int::new_usize(count), Int::new_usize(std::mem::size_of::())) <= Int::new_usize(usize::MAX))]
+ #[ensures(result == address_offset(self, Int::new_usize(count)))]
+ #[no_panic]
+ #[no_panic_ensures_postcondition]
+ unsafe fn add(self, count: usize) -> *const T;
+}
+
+type MutPointer = *mut T;
+#[extern_spec]
+impl MutPointer {
+ #[trusted]
+ #[terminates]
+ #[pure]
+ // FIXME: This is needed because this function is special cased only in the
+ // pure encoder and not in the impure one.
+ #[ensures(result == self.is_null())]
+ #[no_panic]
+ #[no_panic_ensures_postcondition]
+ fn is_null(self) -> bool;
+
+ #[trusted]
+ #[terminates]
+ #[pure]
+ // FIXME: Check provenance.
+ #[structural_requires(Int::new_isize(count) * Int::new_usize(std::mem::size_of::()) <= Int::new_isize(isize::MAX))]
+ #[ensures(result == address_offset_mut(self, Int::new_isize(count)))]
+ #[no_panic]
+ #[no_panic_ensures_postcondition]
+ unsafe fn offset(self, count: isize) -> *mut T;
+
+ #[trusted]
+ #[terminates]
+ #[pure]
+ // FIXME: Properly specify the wrapping arithmetic.
+ #[ensures(result == address_offset_mut(self, Int::new_isize(count)))]
+ #[no_panic]
+ #[no_panic_ensures_postcondition]
+ fn wrapping_offset(self, count: isize) -> *mut T;
+
+ #[trusted]
+ #[terminates]
+ #[pure]
+ // FIXME: Check provenance.
+ // #[structural_requires(Int::new_usize(count) * Int::new_usize(std::mem::size_of::()) <= Int::new_isize(isize::MAX))]
+ #[structural_requires(multiply_int(Int::new_usize(count), Int::new_usize(std::mem::size_of::())) <= Int::new_usize(usize::MAX))]
+ #[ensures(result == address_offset_mut(self, Int::new_usize(count)))]
+ #[no_panic]
+ #[no_panic_ensures_postcondition]
+ unsafe fn add(self, count: usize) -> *mut T;
+
+ #[trusted]
+ #[terminates]
+ #[pure]
+ // FIXME: Check provenance.
+ #[structural_requires(same_allocation(self, origin))]
+ #[structural_requires(multiply_int(address_from(self, origin), Int::new_usize(std::mem::size_of::())) <= Int::new_isize(isize::MAX))]
+ #[structural_requires(address_from(self, origin) >= Int::new_isize(0))]
+ #[ensures(Int::new_isize(result) == address_from(self, origin))]
+ #[no_panic]
+ #[no_panic_ensures_postcondition]
+ unsafe fn offset_from(self, origin: *const T) -> isize;
+
+ #[no_panic]
+ #[no_panic_ensures_postcondition]
+ #[structural_requires(raw!(*self, std::mem::size_of::()))]
+ #[structural_ensures(own!(*self))]
+ #[structural_ensures(unsafe { eval_in!(own!(*self), &*self) } === &val)]
+ pub unsafe fn write(self, val: T);
+}
+
+#[extern_spec]
+impl usize {
+ #[terminates]
+ #[pure]
+ #[no_panic]
+ #[no_panic_ensures_postcondition]
+ fn is_power_of_two(self) -> bool;
+
+ #[terminates]
+ #[pure]
+ #[no_panic]
+ #[no_panic_ensures_postcondition]
+ #[ensures(if multiply_int(Int::new_usize(self), Int::new_usize(rhs)) <= Int::new_usize(usize::MAX) {
+ result == Some(multiply_usize(self, rhs))
+ } else {
+ let none = None;
+ result == none
+ })]
+ fn checked_mul(self, rhs: usize) -> Option;
+
+ #[terminates]
+ #[pure]
+ #[no_panic]
+ #[no_panic_ensures_postcondition]
+ #[ensures(if Int::new_usize(self) + Int::new_usize(rhs) <= Int::new_usize(usize::MAX) {
+ result == Some(self + rhs)
+ } else {
+ let none = None;
+ result == none
+ })]
+ fn checked_add(self, rhs: usize) -> Option;
+
+ #[terminates]
+ #[pure]
+ #[no_panic]
+ #[no_panic_ensures_postcondition]
+ #[ensures(if Int::new_usize(0) <= Int::new_usize(self) - Int::new_usize(rhs) {
+ result == Some(self - rhs)
+ } else {
+ let none = None;
+ result == none
+ })]
+ fn checked_sub(self, rhs: usize) -> Option;
+
+ #[terminates]
+ #[pure]
+ #[no_panic]
+ #[no_panic_ensures_postcondition]
+ #[ensures(self >= rhs ==> result == self - rhs)]
+ fn wrapping_sub(self, rhs: usize) -> usize;
+
+ #[terminates]
+ #[pure]
+ #[no_panic]
+ #[no_panic_ensures_postcondition]
+ #[ensures(Int::new_usize(self) + Int::new_usize(rhs) <= Int::new_usize(usize::MAX) ==> result == self + rhs)]
+ fn wrapping_add(self, rhs: usize) -> usize;
+}
+
+#[extern_spec]
+impl ::core::ptr::NonNull {
+ #[trusted]
+ #[terminates]
+ #[pure]
+ #[no_panic]
+ #[no_panic_ensures_postcondition]
+ pub fn dangling() -> Self;
+
+ #[trusted]
+ #[terminates]
+ #[pure]
+ #[no_panic]
+ #[no_panic_ensures_postcondition]
+ pub fn as_ptr(self) -> *mut T;
+}
+
+#[extern_spec]
+mod core {
+ mod mem {
+ #[pure]
+ #[no_panic]
+ #[no_panic_ensures_postcondition]
+ #[terminates]
+ // FIXME: This is needed because this function is special cased only in the
+ // pure encoder and not in the impure one.
+ #[ensures(result == core::mem::size_of::())]
+ pub fn size_of() -> usize;
+
+ #[pure]
+ #[no_panic]
+ #[no_panic_ensures_postcondition]
+ #[terminates]
+ // FIXME: What are the guarantees?
+ // https://doc.rust-lang.org/std/mem/fn.align_of.html says nothing…
+ #[ensures(result > 0)]
+ // FIXME: This is needed because this function is special cased only in the
+ // pure encoder and not in the impure one.
+ #[ensures(result == core::mem::align_of::())]
+ #[ensures(result.is_power_of_two())]
+ pub fn align_of() -> usize;
+ }
+ mod ptr {
+ #[pure]
+ #[no_panic]
+ #[no_panic_ensures_postcondition]
+ #[ensures(result.is_null())]
+ pub fn null() -> *const T;
+
+ #[no_panic]
+ #[no_panic_ensures_postcondition]
+ #[structural_requires(own!(*src))]
+ #[structural_ensures(raw!(*src, std::mem::size_of::()))]
+ #[structural_ensures(unsafe { old(eval_in!(own!(*src), &*src)) } === &result)]
+ pub unsafe fn read(src: *const T) -> T;
+
+ #[no_panic]
+ #[no_panic_ensures_postcondition]
+ #[structural_requires(raw!(*dst, std::mem::size_of::()))]
+ #[structural_ensures(own!(*dst))]
+ #[structural_ensures(unsafe { eval_in!(own!(*dst), &*dst) } === &src)]
+ pub unsafe fn write(dst: *mut T, src: T);
+
+ #[structural_requires(own!(*to_drop))]
+ #[structural_ensures(raw!(*to_drop, std::mem::size_of::()))]
+ pub unsafe fn drop_in_place(to_drop: *mut T);
+ }
+}
+
+#[extern_spec]
+impl std::alloc::Layout {
+ #[ensures(result.size() == core::mem::size_of::())]
+ #[ensures(result.align() == core::mem::align_of::())]
+ #[no_panic]
+ #[no_panic_ensures_postcondition]
+ fn new() -> std::alloc::Layout;
+
+ // #[requires(core::mem::size_of::() == 4 && core::mem::align_of::() == 4)] // FIXME: We currently support only i32.
+ // Documentation: https://doc.rust-lang.org/reference/type-layout.html#array-layout
+ #[requires(n * core::mem::size_of::() <= (isize::MAX as usize))]
+ #[ensures(
+ (n * core::mem::size_of::() <= (isize::MAX as usize)) == result.is_ok()
+ )]
+ #[ensures(match result {
+ Ok(layout) => {
+ layout.size() == n * core::mem::size_of::() &&
+ layout.align() == core::mem::align_of::()
+ },
+ Err(_) => true,
+ })]
+ #[no_panic]
+ #[no_panic_ensures_postcondition]
+ fn array(n: usize) -> Result;
+
+ #[pure]
+ #[no_panic]
+ #[no_panic_ensures_postcondition]
+ fn size(&self) -> usize;
+
+ #[pure]
+ #[no_panic]
+ #[no_panic_ensures_postcondition]
+ fn align(&self) -> usize;
+}
+
+#[extern_spec]
+mod std {
+ mod alloc {
+ // “It’s undefined behavior if global allocators unwind.”
+ // https://doc.rust-lang.org/std/alloc/trait.GlobalAlloc.html
+ #[no_panic]
+ #[structural_requires(
+ raw!(*ptr, layout.size()) &&
+ raw_dealloc!(*ptr, layout.size(), layout.align())
+ )]
+ pub unsafe fn dealloc(ptr: *mut u8, layout: std::alloc::Layout);
+
+ // “It’s undefined behavior if global allocators unwind.”
+ // https://doc.rust-lang.org/std/alloc/trait.GlobalAlloc.html
+ #[no_panic]
+ #[no_panic_ensures_postcondition]
+ #[structural_requires(
+ layout.size() > 0
+ )]
+ #[ensures(
+ !result.is_null() ==> (
+ raw!(*result, layout.size()) &&
+ raw_dealloc!(*result, layout.size(), layout.align())
+ )
+ )]
+ pub unsafe fn alloc(layout: std::alloc::Layout) -> *mut u8;
+ }
+}
diff --git a/prusti-contracts/prusti-contracts/src/lib.rs b/prusti-contracts/prusti-contracts/src/lib.rs
index 28ab1bce27d..315dd184f07 100644
--- a/prusti-contracts/prusti-contracts/src/lib.rs
+++ b/prusti-contracts/prusti-contracts/src/lib.rs
@@ -1,11 +1,34 @@
-#![no_std]
+// #![no_std] FIXME
-/// A macro for writing a precondition on a function.
+/// A macro for writing a functional precondition on a function.
pub use prusti_contracts_proc_macros::requires;
-/// A macro for writing a postcondition on a function.
+/// A macro for writing a structural precondition on an unsafe function.
+pub use prusti_contracts_proc_macros::structural_requires;
+
+/// A macro to indicate that the type invariant is not required by the function.
+/// FIXME: Remove
+pub use prusti_contracts_proc_macros::not_require;
+
+/// A macro for writing a functional postcondition on a function.
pub use prusti_contracts_proc_macros::ensures;
+/// A macro for writing a functional panic postcondition on a function.
+pub use prusti_contracts_proc_macros::panic_ensures;
+
+/// A macro for writing a structural postcondition on an unsafe function.
+pub use prusti_contracts_proc_macros::structural_ensures;
+
+/// A macro for writing a structural panic postcondition on an unsafe function.
+pub use prusti_contracts_proc_macros::structural_panic_ensures;
+
+/// A macro to indicate that the type invariant is not ensured by the function.
+/// FIXME: Remove
+pub use prusti_contracts_proc_macros::not_ensure;
+
+/// A macro to indicate that the type invariant is broken.
+pub use prusti_contracts_proc_macros::broken_invariant;
+
/// A macro for writing a pledge on a function.
pub use prusti_contracts_proc_macros::after_expiry;
@@ -18,21 +41,59 @@ pub use prusti_contracts_proc_macros::pure;
/// A macro for marking a function as trusted.
pub use prusti_contracts_proc_macros::trusted;
+/// A macro for marking that a function never panics.
+pub use prusti_contracts_proc_macros::no_panic;
+
+/// A macro for marking that if a function did not panic, then we can soundly
+/// assume its postcondition even if the precondition did not hold. (This
+/// basically means that we check the postcondition in memory safety mode.)
+pub use prusti_contracts_proc_macros::no_panic_ensures_postcondition;
+
/// A macro for marking a function as opted into verification.
pub use prusti_contracts_proc_macros::verified;
+/// A macro for marking a pure function as to be non-verified, but axiomatized
+/// when the configuration flag `opt_in_verification` is true.
+pub use prusti_contracts_proc_macros::non_verified_pure;
+
/// A macro for type invariants.
pub use prusti_contracts_proc_macros::invariant;
+/// A macro for structural type invariants. A type with a structural
+/// invariant needs to be managed manually by the user.
+pub use prusti_contracts_proc_macros::structural_invariant;
+
/// A macro for writing a loop body invariant.
pub use prusti_contracts_proc_macros::body_invariant;
+/// A macro for writing a structural loop body invariant.
+pub use prusti_contracts_proc_macros::structural_body_invariant;
+
/// A macro for writing assertions using the full prusti specifications
pub use prusti_contracts_proc_macros::prusti_assert;
+/// A macro for writing structural assertions using prusti syntax
+pub use prusti_contracts_proc_macros::prusti_structural_assert;
+
/// A macro for writing assumptions using prusti syntax
pub use prusti_contracts_proc_macros::prusti_assume;
+/// A macro for writing structural assumptions using prusti syntax
+pub use prusti_contracts_proc_macros::prusti_structural_assume;
+
+/// A macro for case splitting on some expressions.
+pub use prusti_contracts_proc_macros::prusti_split_on;
+
+/// A macro for telling Prusti purification to materialize a predicate instance.
+pub use prusti_contracts_proc_macros::materialize_predicate;
+
+/// A macro for telling Prusti purification that we have a predicate instance
+/// coming from the quantifier.
+pub use prusti_contracts_proc_macros::quantified_predicate;
+
+/// A macro that tells Prusti to assume that the allocation never fails.
+pub use prusti_contracts_proc_macros::assume_allocation_never_fails;
+
/// A macro for writing refutations using prusti syntax
pub use prusti_contracts_proc_macros::prusti_refute;
@@ -57,6 +118,24 @@ pub use prusti_contracts_proc_macros::refine_spec;
/// but omitted during compilation.
pub use prusti_contracts_proc_macros::ghost;
+/// A macro for defining a ghost block that is executed when a specified place
+/// is dropped.
+pub use prusti_contracts_proc_macros::on_drop_unwind;
+
+/// A macro for defining a ghost block that is executed just before dropping the specified value.
+pub use prusti_contracts_proc_macros::before_drop;
+
+/// A macro for defining a ghost block that is executed just after dropping the specified value.
+pub use prusti_contracts_proc_macros::after_drop;
+
+/// A macro for defining a ghost block that is executed when the execution
+/// leaves the block including via panic.
+pub use prusti_contracts_proc_macros::with_finally;
+
+/// A macro that enables precondition checking when verifying in memory safety
+/// mode.
+pub use prusti_contracts_proc_macros::checked;
+
/// A macro to customize how a struct or enum should be printed in a counterexample
pub use prusti_contracts_proc_macros::print_counterexample;
@@ -66,6 +145,102 @@ pub use prusti_contracts_proc_macros::terminates;
/// A macro to annotate body variant of a loop to prove termination
pub use prusti_contracts_proc_macros::body_variant;
+/// A macro to mark the place as manually managed.
+pub use prusti_contracts_proc_macros::manually_manage;
+
+/// A macro to manually pack a place capability.
+pub use prusti_contracts_proc_macros::pack;
+
+/// A macro to manually unpack a place capability.
+pub use prusti_contracts_proc_macros::unpack;
+
+/// Tell Prusti to obtain the specified capability.
+pub use prusti_contracts_proc_macros::obtain;
+
+/// A macro to manually pack a place capability.
+pub use prusti_contracts_proc_macros::pack_ref;
+
+/// A macro to manually unpack a place capability.
+pub use prusti_contracts_proc_macros::unpack_ref;
+
+/// A macro to manually pack a place capability.
+pub use prusti_contracts_proc_macros::pack_mut_ref;
+
+/// A macro to manually unpack a place capability.
+pub use prusti_contracts_proc_macros::unpack_mut_ref;
+
+/// A macro to manually pack a place capability.
+pub use prusti_contracts_proc_macros::pack_mut_ref_obligation;
+
+/// A macro to manually unpack a place capability.
+pub use prusti_contracts_proc_macros::unpack_mut_ref_obligation;
+
+/// A macro to obtain a lifetime of a place.
+pub use prusti_contracts_proc_macros::take_lifetime;
+
+/// A macro to end a lifetime. Note: this macro can be used only in on panic and
+/// finally blocks of `with_finally!`.
+pub use prusti_contracts_proc_macros::end_loan;
+
+/// Set the lifetime of the place to be used for all raw pointer to reference
+/// casts.
+pub use prusti_contracts_proc_macros::set_lifetime_for_raw_pointer_reference_casts;
+
+/// Attach the lifetime to the drop handler.
+pub use prusti_contracts_proc_macros::attach_drop_lifetime;
+
+/// A macro to manually join a place capability.
+pub use prusti_contracts_proc_macros::join;
+
+/// A macro to manually join a range of memory blocks into one.
+pub use prusti_contracts_proc_macros::join_range;
+
+/// A macro to manually split a place capability.
+pub use prusti_contracts_proc_macros::split;
+
+/// A macro to manually split a memory block into a range of memory blocks.
+pub use prusti_contracts_proc_macros::split_range;
+
+/// A macro to stash away a range of own capabilities to get access to
+/// underlying raw memory.
+pub use prusti_contracts_proc_macros::stash_range;
+
+/// A macro to restore the stash away a range of own capabilities.
+pub use prusti_contracts_proc_macros::restore_stash_range;
+
+/// A macro to manually close a reference.
+pub use prusti_contracts_proc_macros::close_ref;
+
+/// A macro to manually open a reference.
+pub use prusti_contracts_proc_macros::open_ref;
+
+/// A macro to manually close a reference.
+pub use prusti_contracts_proc_macros::close_mut_ref;
+
+/// A macro to manually open a reference.
+pub use prusti_contracts_proc_macros::open_mut_ref;
+
+/// A macro to apply the inheritance rule to the specified place.
+pub use prusti_contracts_proc_macros::restore_mut_borrowed;
+
+/// A macro to manually resolve a reference.
+pub use prusti_contracts_proc_macros::resolve;
+
+/// A macro to manually resolve a range of references.
+pub use prusti_contracts_proc_macros::resolve_range;
+
+/// A macro to forget that a place is initialized.
+pub use prusti_contracts_proc_macros::forget_initialization;
+
+/// A macro to forget that a range of places are initialized.
+pub use prusti_contracts_proc_macros::forget_initialization_range;
+
+/// A macro to restore a place capability.
+pub use prusti_contracts_proc_macros::restore;
+
+/// A macro to set a specific field of the union as active.
+pub use prusti_contracts_proc_macros::set_union_active_field;
+
#[cfg(not(feature = "prusti"))]
mod private {
use core::marker::PhantomData;
@@ -119,6 +294,23 @@ mod private {
pub struct Ghost {
_phantom: PhantomData,
}
+
+ pub struct GhostDrop;
+
+ impl Drop for GhostDrop {
+ fn drop(&mut self) {}
+ }
+
+ /// A type allowing to refer to a lifetime in places where Rust syntax does
+ /// not allow it. It should not be possible to construct from Rust code,
+ /// hence the private unit inside.
+ pub struct Lifetime(());
+
+ /// A methematical type representing a machine byte.
+ pub struct Byte(());
+
+ /// A methematical type representing a sequence of machine bytes.
+ pub struct Bytes(());
}
#[cfg(feature = "prusti")]
@@ -131,15 +323,21 @@ mod private {
/// A macro for defining a closure with a specification.
pub use prusti_contracts_proc_macros::{closure, pure, trusted};
- pub fn prusti_set_union_active_field(_arg: T) {
- unreachable!();
- }
+ // pub fn prusti_set_union_active_field(_arg: T) {
+ // unreachable!();
+ // }
#[pure]
pub fn prusti_terminates_trusted() -> Int {
Int::new(1)
}
+ /// A type allowing to refer to a lifetime in places where Rust syntax does
+ /// not allow it. It should not be possible to construct from Rust code,
+ /// hence the private unit inside.
+ #[derive(Copy, Clone)]
+ pub struct Lifetime(());
+
/// a mathematical (unbounded) integer type
/// it should not be constructed from running rust code, hence the private unit inside
#[derive(Copy, Clone, PartialEq, Eq)]
@@ -153,6 +351,18 @@ mod private {
pub fn new_usize(_: usize) -> Self {
panic!()
}
+
+ pub fn new_isize(_: isize) -> Self {
+ panic!()
+ }
+
+ pub fn to_usize(&self) -> usize {
+ panic!()
+ }
+
+ pub fn to_isize(&self) -> isize {
+ panic!()
+ }
}
macro_rules! __int_dummy_trait_impls__ {
@@ -325,6 +535,20 @@ mod private {
panic!()
}
}
+
+ pub struct GhostDrop;
+
+ impl Drop for GhostDrop {
+ fn drop(&mut self) {}
+ }
+
+ /// A methematical type representing a machine byte.
+ #[derive(Copy, Clone, PartialEq, Eq)]
+ pub struct Byte(());
+
+ /// A methematical type representing a sequence of machine bytes.
+ #[derive(Copy, Clone, PartialEq, Eq)]
+ pub struct Bytes(());
}
/// This function is used to evaluate an expression in the context just
@@ -368,4 +592,558 @@ pub fn snapshot_equality(_l: T, _r: T) -> bool {
true
}
+#[doc(hidden)]
+#[trusted]
+pub fn prusti_manually_manage(_arg: T) {
+ unreachable!();
+}
+
+#[doc(hidden)]
+#[trusted]
+pub fn prusti_pack_place(_arg: T) {
+ unreachable!();
+}
+
+#[doc(hidden)]
+#[trusted]
+pub fn prusti_unpack_place(_arg: T) {
+ unreachable!();
+}
+
+#[doc(hidden)]
+#[trusted]
+pub fn prusti_obtain_place(_arg: T) {
+ unreachable!();
+}
+
+#[doc(hidden)]
+#[trusted]
+pub fn prusti_pack_ref_place(_lifetime_name: &'static str, _arg: T) {
+ unreachable!();
+}
+
+#[doc(hidden)]
+#[trusted]
+pub fn prusti_unpack_ref_place(_lifetime_name: &'static str, _arg: T) {
+ unreachable!();
+}
+
+#[doc(hidden)]
+#[trusted]
+pub fn prusti_pack_mut_ref_place(_lifetime_name: &'static str, _arg: T) {
+ unreachable!();
+}
+
+#[doc(hidden)]
+#[trusted]
+pub fn prusti_unpack_mut_ref_place(_lifetime_name: &'static str, _arg: T) {
+ unreachable!();
+}
+
+#[doc(hidden)]
+#[trusted]
+pub fn prusti_pack_mut_ref_place_obligation(_lifetime_name: &'static str, _arg: T) {
+ unreachable!();
+}
+
+#[doc(hidden)]
+#[trusted]
+pub fn prusti_unpack_mut_ref_place_obligation(_lifetime_name: &'static str, _arg: T) {
+ unreachable!();
+}
+
+#[doc(hidden)]
+#[trusted]
+pub fn prusti_take_lifetime(_arg: T, _lifetime_name: &'static str) -> Lifetime {
+ unreachable!();
+}
+
+#[doc(hidden)]
+#[trusted]
+pub fn prusti_end_loan(_lifetime_name: &'static str) {
+ unreachable!();
+}
+
+#[doc(hidden)]
+#[trusted]
+pub fn prusti_set_lifetime_for_raw_pointer_reference_casts(_arg: T) {
+ unreachable!();
+}
+
+#[doc(hidden)]
+#[trusted]
+pub fn prusti_attach_drop_lifetime(_guard: T1, _reference: T2) {
+ unreachable!();
+}
+
+#[doc(hidden)]
+#[trusted]
+pub fn prusti_join_place(_arg: T) {
+ unreachable!();
+}
+
+#[doc(hidden)]
+#[trusted]
+pub fn prusti_join_range(_arg: T, _start_index: usize, _end_index: usize) {
+ unreachable!();
+}
+
+#[doc(hidden)]
+#[trusted]
+pub fn prusti_split_place(_arg: T) {
+ unreachable!();
+}
+
+#[doc(hidden)]
+#[trusted]
+pub fn prusti_split_range(_arg: T, _start_index: usize, _end_index: usize) {
+ unreachable!();
+}
+
+#[doc(hidden)]
+#[trusted]
+pub fn prusti_stash_range(
+ _arg: T,
+ _start_index: usize,
+ _end_index: usize,
+ _witness: &'static str,
+) {
+ unreachable!();
+}
+
+#[doc(hidden)]
+#[trusted]
+pub fn prusti_restore_stash_range(_arg: T, _new_start_index: usize, _witness: &'static str) {
+ unreachable!();
+}
+
+#[doc(hidden)]
+#[trusted]
+/// We need to pass `_arg` to make sure the lifetime covers the closing of the
+/// reference.
+pub fn prusti_close_ref_place(_arg: T, _witness: &'static str) {
+ unreachable!();
+}
+
+#[doc(hidden)]
+#[trusted]
+pub fn prusti_open_ref_place(_lifetime: &'static str, _arg: T, _witness: &'static str) {
+ unreachable!();
+}
+
+#[doc(hidden)]
+#[trusted]
+/// We need to pass `_arg` to make sure the lifetime covers the closing of the
+/// reference.
+pub fn prusti_close_mut_ref_place(_arg: T, _witness: &'static str) {
+ unreachable!();
+}
+
+#[doc(hidden)]
+#[trusted]
+pub fn prusti_open_mut_ref_place(_lifetime: &'static str, _arg: T, _witness: &'static str) {
+ unreachable!();
+}
+
+#[doc(hidden)]
+#[trusted]
+pub fn prusti_restore_mut_borrowed(_referencing: T1, _referenced: T2) {
+ unreachable!();
+}
+
+#[doc(hidden)]
+#[trusted]
+pub fn prusti_resolve(_arg: T) {
+ unreachable!();
+}
+
+#[doc(hidden)]
+#[trusted]
+pub fn prusti_materialize_predicate(_arg: T) {
+ unreachable!();
+}
+
+#[doc(hidden)]
+#[trusted]
+pub fn prusti_quantified_predicate(_arg: T) {
+ unreachable!();
+}
+
+#[doc(hidden)]
+#[trusted]
+#[no_panic]
+#[no_panic_ensures_postcondition]
+#[ensures(allocation_never_fails())]
+pub fn prusti_assume_allocation_never_fails() {
+ unreachable!();
+}
+
+#[doc(hidden)]
+#[trusted]
+pub fn prusti_resolve_range(
+ _lifetime: &'static str,
+ _arg: T,
+ _predicate_range_start_index: usize,
+ _predicate_range_end_index: usize,
+ _start_index: usize,
+ _end_index: usize,
+) {
+ unreachable!();
+}
+
+#[doc(hidden)]
+#[trusted]
+#[pure]
+pub fn prusti_forget_initialization(_arg: T) {
+ unreachable!();
+}
+
+#[doc(hidden)]
+#[trusted]
+#[pure]
+pub fn prusti_forget_initialization_range(_address: T, _start: usize, _end: usize) {
+ unreachable!();
+}
+
+#[doc(hidden)]
+#[trusted]
+pub fn prusti_on_drop_unwind(_arg: T) {
+ unreachable!();
+}
+
+#[doc(hidden)]
+#[trusted]
+pub fn prusti_before_drop(_arg: T) {
+ unreachable!();
+}
+
+#[doc(hidden)]
+#[trusted]
+pub fn prusti_after_drop(_arg: T) {
+ unreachable!();
+}
+
+#[doc(hidden)]
+#[trusted]
+pub fn prusti_restore_place(_arg1: T, _arg2: T) {
+ unreachable!();
+}
+
+#[doc(hidden)]
+#[trusted]
+pub fn prusti_set_union_active_field(_arg: T) {
+ unreachable!();
+}
+
+/// Indicates that the expression should be evaluated assuming that the given
+/// predicate is present.
+#[doc(hidden)]
+#[trusted]
+pub fn prusti_eval_in(_predicate: bool, _expression: T) -> T {
+ unreachable!();
+}
+
+/// Indicates that the expression should be evaluated assuming that the given
+/// quantified predicate is present.
+#[doc(hidden)]
+#[trusted]
+pub fn prusti_eval_in_quantified(_predicate: bool, _expression: T) -> T {
+ unreachable!();
+}
+
+#[macro_export]
+macro_rules! eval_in {
+ ($predicate:expr, $expression:expr) => {
+ $crate::prusti_eval_in($predicate, $expression)
+ };
+}
+
+#[macro_export]
+macro_rules! eval_in_quantified {
+ ($predicate:expr, $expression:expr) => {
+ $crate::prusti_eval_in_quantified($predicate, $expression)
+ };
+}
+
+/// Indicates that the parameter's or return value invariant is broken.
+#[doc(hidden)]
+#[trusted]
+#[pure]
+pub fn prusti_broken_invariant(_place: T) -> bool {
+ unreachable!();
+}
+
+#[doc(hidden)]
+#[trusted]
+pub fn prusti_old_local(_local: &T) -> T {
+ unreachable!();
+}
+
+#[macro_export]
+macro_rules! old_local {
+ ($local:expr) => {
+ $crate::prusti_old_local(unsafe { &$local })
+ };
+}
+
+/// Indicates that we have the `own` capability to the specified place.
+#[doc(hidden)]
+#[trusted]
+pub fn prusti_own(_place: T) -> bool {
+ unreachable!();
+}
+
+#[macro_export]
+macro_rules! own {
+ ($place:expr) => {
+ $crate::prusti_own(unsafe { core::ptr::addr_of!($place) })
+ };
+}
+
+/// Indicates that we have the `own` capability to the specified range.
+#[doc(hidden)]
+#[trusted]
+pub fn prusti_own_range(_address: T, _start: usize, _end: usize) -> bool {
+ unreachable!();
+}
+
+#[macro_export]
+macro_rules! own_range {
+ ($address:expr, $end:expr) => {
+ $crate::prusti_own_range($address, 0, $end)
+ };
+ ($address:expr, $start:expr, $end:expr) => {
+ $crate::prusti_own_range($address, $start, $end)
+ };
+}
+
+/// Indicates that we have the shared reference capability to the specified
+/// place.
+#[doc(hidden)]
+#[trusted]
+pub fn prusti_shr(_place: T) -> bool {
+ unreachable!();
+}
+
+#[macro_export]
+macro_rules! shr {
+ ($place:expr) => {
+ $crate::prusti_shr(unsafe { core::ptr::addr_of!($place) })
+ };
+}
+
+/// Indicates that we have the unique reference capability to the specified
+/// place.
+#[doc(hidden)]
+#[trusted]
+pub fn prusti_unq(_lifetime: T1, _place: T2) -> bool {
+ unreachable!();
+}
+
+/// Indicates that we have the unique reference capability to the specified
+/// place.
+#[doc(hidden)]
+#[trusted]
+pub fn prusti_unq_real_lifetime(_lifetime: T1, _place: T2) -> bool {
+ unreachable!();
+}
+
+#[macro_export]
+macro_rules! unq {
+ ($lifetime:ident, $place:expr) => {
+ $crate::prusti_unq(stringify!($lifetime), unsafe {
+ core::ptr::addr_of!($place)
+ })
+ };
+ ($lifetime:lifetime, $place:expr) => {
+ $crate::prusti_unq_real_lifetime(stringify!($lifetime), unsafe {
+ core::ptr::addr_of!($place)
+ })
+ };
+}
+
+/// Indicates that we have the unique reference capability to the specified range.
+#[doc(hidden)]
+#[trusted]
+pub fn prusti_unq_real_lifetime_range(
+ _lifetime: L,
+ _address: T,
+ _start: usize,
+ _end: usize,
+) -> bool {
+ unreachable!();
+}
+
+/// Deref a raw pointer with the specified offset.
+#[doc(hidden)]
+#[trusted]
+pub unsafe fn prusti_deref_own(_address: *const T, _index: usize) -> T {
+ unreachable!();
+}
+
+#[macro_export]
+macro_rules! deref_own {
+ ($address:expr, $index:expr) => {
+ unsafe { $crate::prusti_deref_own($address, $index) }
+ };
+}
+
+/// Obtain the bytes of the specified memory block.
+#[doc(hidden)]
+#[trusted]
+pub fn prusti_bytes(_address: T, _length: usize) -> Bytes {
+ unreachable!();
+}
+
+#[macro_export]
+macro_rules! bytes {
+ ($address:expr, $length:expr) => {
+ $crate::prusti_bytes(unsafe { core::ptr::addr_of!($address) }, $length)
+ };
+}
+
+/// Obtain the bytes of the specified memory block.
+#[doc(hidden)]
+#[trusted]
+#[terminates]
+#[no_panic]
+pub fn prusti_bytes_ptr(_pointer: *const T, _length: usize) -> Bytes {
+ unreachable!();
+}
+
+#[macro_export]
+macro_rules! bytes_ptr {
+ ($pointer:expr, $length:expr) => {
+ $crate::prusti_bytes_ptr(unsafe { $pointer }, $length)
+ };
+}
+
+/// Read the byte at the given index.
+///
+/// FIXME: This function does not check bounds. Instead, it returns garbage in
+/// case of out-of-bounds
+pub fn read_byte(_bytes: Bytes, _index: usize) -> Byte {
+ unreachable!();
+}
+
+/// Check whether `element_address` is contained in the range starting at
+/// `start_address` and having the specified size.
+pub fn range_contains(
+ _start_address: *const T,
+ _range_size: usize,
+ _element_address: *const T,
+) -> bool {
+ unreachable!();
+}
+
+/// Indicates that we have the `raw` capability to the specified address.
+#[doc(hidden)]
+#[trusted]
+pub fn prusti_raw(_address: T, _size: usize) -> bool {
+ true
+}
+
+#[macro_export]
+macro_rules! raw {
+ ($place:expr, $size: expr) => {
+ $crate::prusti_raw(unsafe { core::ptr::addr_of!($place) }, $size)
+ };
+}
+
+/// Indicates that we have the `raw` capability to the specified range.
+#[doc(hidden)]
+#[trusted]
+pub fn prusti_raw_range(_address: T, _size: usize, _start: usize, _end: usize) -> bool {
+ unreachable!();
+}
+
+/// Indicates that we have the `raw` capability for locations for which the
+/// condition holds.
+#[doc(hidden)]
+#[trusted]
+pub fn prusti_raw_range_guarded(
+ _address: T,
+ _size: usize,
+ _trigger_set: S,
+ _closure: F,
+) -> bool {
+ unreachable!();
+}
+
+/// Indicates that we have the capability to deallocate.
+#[doc(hidden)]
+#[trusted]
+pub fn prusti_raw_dealloc(_address: T, _size: usize) -> bool {
+ true
+}
+
+#[macro_export]
+macro_rules! raw_dealloc {
+ ($place:expr, $size: expr, $align: expr) => {
+ $crate::prusti_raw_dealloc(unsafe { core::ptr::addr_of!($place) }, $size)
+ };
+}
+
+/// Temporarily unpacks the owned predicate at the given location.
+#[doc(hidden)]
+#[trusted]
+pub fn prusti_unpacking(_place: T, _body: U) -> U {
+ unimplemented!()
+}
+
+#[macro_export]
+macro_rules! unpacking {
+ ($place:expr, $body: expr) => {
+ $crate::prusti_unpacking(unsafe { core::ptr::addr_of!($place) }, $body)
+ };
+}
+
+/// A ghost operation for computing an offset of the pointer.
+pub fn address_offset_mut(_ptr: *mut T, _count: Int) -> *mut T {
+ unreachable!();
+}
+
+/// A ghost operation for computing an offset of the pointer.
+pub fn address_offset(_ptr: *const T, _count: Int) -> *const T {
+ unreachable!();
+}
+
+/// A ghost operation for computing the distance between two pointers in the units of `T`.
+pub fn address_from(_ptr: *const T, _origin: *const T) -> Int {
+ unreachable!();
+}
+
+/// A ghost operation for expressing that the two pointers belong to the same allocation.
+pub fn same_allocation(_ptr1: *const T, _ptr2: *const T) -> bool {
+ unreachable!();
+}
+
+/// A ghost operation for expressing that the address belongs to a fresh
+/// allocation (different from all others).
+pub fn fresh_allocation(_ptr1: *const T) -> bool {
+ unreachable!();
+}
+
+#[pure]
+#[terminates]
+pub fn multiply_int(_left: Int, _right: Int) -> Int {
+ unreachable!();
+}
+
+#[pure]
+#[terminates]
+#[requires(multiply_int(Int::new_usize(left), Int::new_usize(right)) <= Int::new_usize(usize::MAX))]
+#[ensures(multiply_int(Int::new_usize(left), Int::new_usize(right)) == Int::new_usize(result))]
+pub fn multiply_usize(left: usize, right: usize) -> usize {
+ unreachable!();
+}
+
+#[trusted]
+#[pure]
+#[no_panic]
+#[no_panic_ensures_postcondition]
+pub fn allocation_never_fails() -> bool {
+ unreachable!();
+}
+
pub use private::*;
diff --git a/prusti-contracts/prusti-specs/src/lib.rs b/prusti-contracts/prusti-specs/src/lib.rs
index e2383573575..67ae1811893 100644
--- a/prusti-contracts/prusti-specs/src/lib.rs
+++ b/prusti-contracts/prusti-specs/src/lib.rs
@@ -14,6 +14,7 @@ mod extern_spec_rewriter;
mod type_cond_specs;
mod parse_closure_macro;
mod parse_quote_spanned;
+mod parse_ghost_macros;
mod predicate;
mod rewriter;
mod span_overrider;
@@ -23,6 +24,7 @@ mod type_model;
mod user_provided_type_params;
mod print_counterexample;
+use parse_ghost_macros::{OnDropUnwind, WithFinally};
use proc_macro2::{Span, TokenStream, TokenTree};
use quote::{quote, quote_spanned, ToTokens};
use rewriter::AstRewriter;
@@ -70,7 +72,13 @@ fn extract_prusti_attributes(
if let Ok(attr_kind) = attr.path.segments[idx].ident.to_string().try_into() {
let tokens = match attr_kind {
SpecAttributeKind::Requires
+ | SpecAttributeKind::StructuralRequires
| SpecAttributeKind::Ensures
+ | SpecAttributeKind::PanicEnsures
+ | SpecAttributeKind::StructuralEnsures
+ | SpecAttributeKind::StructuralPanicEnsures
+ | SpecAttributeKind::NotRequire
+ | SpecAttributeKind::NotEnsure
| SpecAttributeKind::AfterExpiry
| SpecAttributeKind::AssertOnExpiry
| SpecAttributeKind::RefineSpec => {
@@ -87,7 +95,10 @@ fn extract_prusti_attributes(
| SpecAttributeKind::Terminates
| SpecAttributeKind::Trusted
| SpecAttributeKind::Predicate
- | SpecAttributeKind::Verified => {
+ | SpecAttributeKind::Verified
+ | SpecAttributeKind::NonVerifiedPure
+ | SpecAttributeKind::NoPanic
+ | SpecAttributeKind::NoPanicEnsuresPostcondition => {
assert!(attr.tokens.is_empty(), "Unexpected shape of an attribute.");
attr.tokens
}
@@ -162,13 +173,30 @@ fn generate_spec_and_assertions(
for (attr_kind, attr_tokens) in prusti_attributes.drain(..) {
let rewriting_result = match attr_kind {
SpecAttributeKind::Requires => generate_for_requires(attr_tokens, item),
+ SpecAttributeKind::StructuralRequires => {
+ generate_for_structural_requires(attr_tokens, item)
+ }
SpecAttributeKind::Ensures => generate_for_ensures(attr_tokens, item),
+ SpecAttributeKind::PanicEnsures => generate_for_panic_ensures(attr_tokens, item),
+ SpecAttributeKind::StructuralEnsures => {
+ generate_for_structural_ensures(attr_tokens, item)
+ }
+ SpecAttributeKind::StructuralPanicEnsures => {
+ generate_for_structural_panic_ensures(attr_tokens, item)
+ }
+ SpecAttributeKind::NotRequire => generate_for_not_require(attr_tokens, item),
+ SpecAttributeKind::NotEnsure => generate_for_not_ensure(attr_tokens, item),
SpecAttributeKind::AfterExpiry => generate_for_after_expiry(attr_tokens, item),
SpecAttributeKind::AssertOnExpiry => generate_for_assert_on_expiry(attr_tokens, item),
SpecAttributeKind::Pure => generate_for_pure(attr_tokens, item),
SpecAttributeKind::Verified => generate_for_verified(attr_tokens, item),
+ SpecAttributeKind::NonVerifiedPure => generate_for_non_verified_pure(attr_tokens, item),
SpecAttributeKind::Terminates => generate_for_terminates(attr_tokens, item),
SpecAttributeKind::Trusted => generate_for_trusted(attr_tokens, item),
+ SpecAttributeKind::NoPanic => generate_for_no_panic(attr_tokens, item),
+ SpecAttributeKind::NoPanicEnsuresPostcondition => {
+ generate_for_no_panic_ensures_postcondition(attr_tokens, item)
+ }
// Predicates are handled separately below; the entry in the SpecAttributeKind enum
// only exists so we successfully parse it and emit an error in
// `check_incompatible_attrs`; so we'll never reach here.
@@ -201,6 +229,45 @@ fn generate_for_requires(attr: TokenStream, item: &untyped::AnyFnItem) -> Genera
))
}
+/// Generate spec items and attributes to typecheck the and later retrieve "structural_requires" annotations.
+fn generate_for_structural_requires(
+ attr: TokenStream,
+ item: &untyped::AnyFnItem,
+) -> GeneratedResult {
+ let mut rewriter = rewriter::AstRewriter::new();
+ let spec_id = rewriter.generate_spec_id();
+ let spec_id_str = spec_id.to_string();
+ let spec_item =
+ rewriter.process_assertion(rewriter::SpecItemType::Precondition, spec_id, attr, item)?;
+ Ok((
+ vec![spec_item],
+ vec![parse_quote_spanned! {item.span()=>
+ #[prusti::pre_structural_spec_id_ref = #spec_id_str]
+ }],
+ ))
+}
+
+/// Generate spec items and attributes to typecheck and later retrieve
+/// "not_require" annotations.
+fn generate_for_not_require(attr: TokenStream, item: &untyped::AnyFnItem) -> GeneratedResult {
+ let attr = quote! { prusti_broken_invariant(#attr) };
+ let mut rewriter = rewriter::AstRewriter::new();
+ let spec_id = rewriter.generate_spec_id();
+ let spec_id_str = spec_id.to_string();
+ let spec_item = rewriter.process_assertion(
+ rewriter::SpecItemType::BrokenPrecondition,
+ spec_id,
+ attr,
+ item,
+ )?;
+ Ok((
+ vec![spec_item],
+ vec![parse_quote_spanned! {item.span()=>
+ #[prusti::pre_broken_spec_id_ref = #spec_id_str]
+ }],
+ ))
+}
+
/// Generate spec items and attributes to typecheck the and later retrieve "ensures" annotations.
fn generate_for_ensures(attr: TokenStream, item: &untyped::AnyFnItem) -> GeneratedResult {
let mut rewriter = rewriter::AstRewriter::new();
@@ -216,6 +283,81 @@ fn generate_for_ensures(attr: TokenStream, item: &untyped::AnyFnItem) -> Generat
))
}
+/// Generate spec items and attributes to typecheck the and later retrieve
+/// "panic_ensures" annotations.
+fn generate_for_panic_ensures(attr: TokenStream, item: &untyped::AnyFnItem) -> GeneratedResult {
+ let mut rewriter = rewriter::AstRewriter::new();
+ let spec_id = rewriter.generate_spec_id();
+ let spec_id_str = spec_id.to_string();
+ let spec_item =
+ rewriter.process_assertion(rewriter::SpecItemType::Postcondition, spec_id, attr, item)?;
+ Ok((
+ vec![spec_item],
+ vec![parse_quote_spanned! {item.span()=>
+ #[prusti::post_panic_spec_id_ref = #spec_id_str]
+ }],
+ ))
+}
+
+/// Generate spec items and attributes to typecheck the and later retrieve
+/// "structural_ensures" annotations.
+fn generate_for_structural_ensures(
+ attr: TokenStream,
+ item: &untyped::AnyFnItem,
+) -> GeneratedResult {
+ let mut rewriter = rewriter::AstRewriter::new();
+ let spec_id = rewriter.generate_spec_id();
+ let spec_id_str = spec_id.to_string();
+ let spec_item =
+ rewriter.process_assertion(rewriter::SpecItemType::Postcondition, spec_id, attr, item)?;
+ Ok((
+ vec![spec_item],
+ vec![parse_quote_spanned! {item.span()=>
+ #[prusti::post_structural_spec_id_ref = #spec_id_str]
+ }],
+ ))
+}
+
+/// Generate spec items and attributes to typecheck the and later retrieve
+/// "structural_ensures" annotations.
+fn generate_for_structural_panic_ensures(
+ attr: TokenStream,
+ item: &untyped::AnyFnItem,
+) -> GeneratedResult {
+ let mut rewriter = rewriter::AstRewriter::new();
+ let spec_id = rewriter.generate_spec_id();
+ let spec_id_str = spec_id.to_string();
+ let spec_item =
+ rewriter.process_assertion(rewriter::SpecItemType::Postcondition, spec_id, attr, item)?;
+ Ok((
+ vec![spec_item],
+ vec![parse_quote_spanned! {item.span()=>
+ #[prusti::post_structural_panic_spec_id_ref = #spec_id_str]
+ }],
+ ))
+}
+
+/// Generate spec items and attributes to typecheck and later retrieve
+/// "not_ensure" annotations.
+fn generate_for_not_ensure(attr: TokenStream, item: &untyped::AnyFnItem) -> GeneratedResult {
+ let attr = quote! { prusti_broken_invariant(#attr) };
+ let mut rewriter = rewriter::AstRewriter::new();
+ let spec_id = rewriter.generate_spec_id();
+ let spec_id_str = spec_id.to_string();
+ let spec_item = rewriter.process_assertion(
+ rewriter::SpecItemType::BrokenPostcondition,
+ spec_id,
+ attr,
+ item,
+ )?;
+ Ok((
+ vec![spec_item],
+ vec![parse_quote_spanned! {item.span()=>
+ #[prusti::post_broken_spec_id_ref = #spec_id_str]
+ }],
+ ))
+}
+
/// Generate spec items and attributes to typecheck and later retrieve "after_expiry" annotations.
fn generate_for_after_expiry(attr: TokenStream, item: &untyped::AnyFnItem) -> GeneratedResult {
let mut rewriter = rewriter::AstRewriter::new();
@@ -314,6 +456,23 @@ fn generate_for_verified(attr: TokenStream, item: &untyped::AnyFnItem) -> Genera
))
}
+/// Generate spec items and attributes to typecheck and later retrieve "non_verified_pure" annotations.
+fn generate_for_non_verified_pure(attr: TokenStream, item: &untyped::AnyFnItem) -> GeneratedResult {
+ if !attr.is_empty() {
+ return Err(syn::Error::new(
+ attr.span(),
+ "the `#[non_verified_pure]` attribute does not take parameters",
+ ));
+ }
+
+ Ok((
+ vec![],
+ vec![parse_quote_spanned! {item.span()=>
+ #[prusti::non_verified_pure]
+ }],
+ ))
+}
+
/// Generate spec items and attributes to typecheck and later retrieve "pure" annotations, but encoded as a referenced separate function that type-conditional spec refinements can apply trait bounds to.
fn generate_for_pure_refinements(item: &untyped::AnyFnItem) -> GeneratedResult {
let mut rewriter = rewriter::AstRewriter::new();
@@ -346,6 +505,45 @@ fn generate_for_trusted(attr: TokenStream, item: &untyped::AnyFnItem) -> Generat
))
}
+/// Generate spec items and attributes to typecheck and later retrieve
+/// "no_panic" annotations.
+fn generate_for_no_panic(attr: TokenStream, item: &untyped::AnyFnItem) -> GeneratedResult {
+ if !attr.is_empty() {
+ return Err(syn::Error::new(
+ attr.span(),
+ "the `#[no_panic]` attribute does not take parameters",
+ ));
+ }
+
+ Ok((
+ vec![],
+ vec![parse_quote_spanned! {item.span()=>
+ #[prusti::no_panic]
+ }],
+ ))
+}
+
+/// Generate spec items and attributes to typecheck and later retrieve
+/// "no_panic_ensures_postcondition" annotations.
+fn generate_for_no_panic_ensures_postcondition(
+ attr: TokenStream,
+ item: &untyped::AnyFnItem,
+) -> GeneratedResult {
+ if !attr.is_empty() {
+ return Err(syn::Error::new(
+ attr.span(),
+ "the `#[no_panic_ensures_postcondition]` attribute does not take parameters",
+ ));
+ }
+
+ Ok((
+ vec![],
+ vec![parse_quote_spanned! {item.span()=>
+ #[prusti::no_panic_ensures_postcondition]
+ }],
+ ))
+}
+
/// Generate spec items and attributes to typecheck and later retrieve "trusted" annotations.
fn generate_for_trusted_for_types(attr: TokenStream, item: &syn::DeriveInput) -> GeneratedResult {
if !attr.is_empty() {
@@ -422,6 +620,10 @@ pub fn body_invariant(tokens: TokenStream) -> TokenStream {
generate_expression_closure(&AstRewriter::process_loop_invariant, tokens)
}
+pub fn structural_body_invariant(tokens: TokenStream) -> TokenStream {
+ generate_expression_closure(&AstRewriter::process_structural_loop_invariant, tokens)
+}
+
pub fn prusti_assertion(tokens: TokenStream) -> TokenStream {
generate_expression_closure(&AstRewriter::process_prusti_assertion, tokens)
}
@@ -434,6 +636,18 @@ pub fn prusti_refutation(tokens: TokenStream) -> TokenStream {
generate_expression_closure(&AstRewriter::process_prusti_refutation, tokens)
}
+pub fn prusti_structural_assert(tokens: TokenStream) -> TokenStream {
+ generate_expression_closure(&AstRewriter::process_prusti_structural_assertion, tokens)
+}
+
+pub fn prusti_structural_assume(tokens: TokenStream) -> TokenStream {
+ generate_expression_closure(&AstRewriter::process_prusti_structural_assumption, tokens)
+}
+
+pub fn prusti_split_on(tokens: TokenStream) -> TokenStream {
+ generate_expression_closure(&AstRewriter::process_prusti_split, tokens)
+}
+
/// Generates the TokenStream encoding an expression using prusti syntax
/// Used for body invariants, assertions, and assumptions
fn generate_expression_closure(
@@ -453,6 +667,23 @@ fn generate_expression_closure(
}
}
+fn prusti_specification_expression(
+ tokens: TokenStream,
+) -> syn::Result<(SpecificationId, TokenStream)> {
+ let mut rewriter = rewriter::AstRewriter::new();
+ let spec_id = rewriter.generate_spec_id();
+ let closure = rewriter.process_prusti_specification_expression(spec_id, tokens)?;
+ let callsite_span = Span::call_site();
+ let tokens = quote_spanned! {callsite_span=>
+ #[allow(unused_must_use, unused_variables, unused_braces, unused_parens)]
+ #[prusti::specs_version = #SPECS_VERSION]
+ if false {
+ #closure
+ }
+ };
+ Ok((spec_id, tokens))
+}
+
pub fn closure(tokens: TokenStream) -> TokenStream {
let cl_spec: ClosureWithSpec = handle_result!(syn::parse(tokens.into()));
let callsite_span = Span::call_site();
@@ -710,7 +941,7 @@ pub fn trusted(attr: TokenStream, tokens: TokenStream) -> TokenStream {
}
}
-pub fn invariant(attr: TokenStream, tokens: TokenStream) -> TokenStream {
+pub fn invariant(attr: TokenStream, tokens: TokenStream, is_structural: bool) -> TokenStream {
let mut rewriter = rewriter::AstRewriter::new();
let spec_id = rewriter.generate_spec_id();
let spec_id_str = spec_id.to_string();
@@ -721,41 +952,60 @@ pub fn invariant(attr: TokenStream, tokens: TokenStream) -> TokenStream {
// clippy false positive (https://github.com/rust-lang/rust-clippy/issues/10577)
#[allow(clippy::redundant_clone)]
let item_ident = item.ident.clone();
-
+ let item_name_structural = if is_structural {
+ "structural"
+ } else {
+ "non_structural"
+ };
let item_name = syn::Ident::new(
- &format!("prusti_invariant_item_{item_ident}_{spec_id}"),
+ &format!("prusti_invariant_item_{item_name_structural}_{item_ident}_{spec_id}"),
item_span,
);
let attr = handle_result!(parse_prusti(attr));
+ let is_structural_tokens = if is_structural {
+ quote_spanned!(item_span => #[prusti::type_invariant_structural])
+ } else {
+ quote_spanned!(item_span => #[prusti::type_invariant_non_structural])
+ };
// TODO: move some of this to AstRewriter?
// see AstRewriter::generate_spec_item_fn for explanation of syntax below
let spec_item: syn::ItemFn = parse_quote_spanned! {item_span=>
#[allow(unused_must_use, unused_parens, unused_variables, dead_code, non_snake_case)]
#[prusti::spec_only]
#[prusti::type_invariant_spec]
+ #is_structural_tokens
#[prusti::spec_id = #spec_id_str]
fn #item_name(self) -> bool {
!!((#attr) : bool)
}
};
- // clippy false positive (https://github.com/rust-lang/rust-clippy/issues/10577)
- #[allow(clippy::redundant_clone)]
- let generics = item.generics.clone();
+ let generics = &item.generics;
+
+ let mut generic_params = generics.params.clone();
+ for param in &mut generic_params {
+ match param {
+ syn::GenericParam::Type(param) => {
+ param.attrs = Vec::new();
+ param.colon_token = None;
+ param.bounds = syn::punctuated::Punctuated::new();
+ param.eq_token = None;
+ param.default = None;
+ }
+ syn::GenericParam::Lifetime(param) => {
+ param.attrs = Vec::new();
+ param.colon_token = None;
+ param.bounds = syn::punctuated::Punctuated::new();
+ }
+ syn::GenericParam::Const(_) => {}
+ }
+ }
- let generics_idents = generics
- .params
- .iter()
- .filter_map(|generic_param| match generic_param {
- syn::GenericParam::Type(type_param) => Some(type_param.ident.clone()),
- _ => None,
- })
- .collect::>();
// TODO: similarly to extern_specs, don't generate an actual impl
let item_impl: syn::ItemImpl = parse_quote_spanned! {item_span=>
- impl #generics #item_ident < #generics_idents > {
+ impl #generics #item_ident < #generic_params > {
#spec_item
}
};
@@ -865,15 +1115,36 @@ fn extract_prusti_attributes_for_types(
if let Ok(attr_kind) = attr.path.segments[0].ident.to_string().try_into() {
let tokens = match attr_kind {
SpecAttributeKind::Requires => unreachable!("requires on type"),
+ SpecAttributeKind::StructuralRequires => {
+ unreachable!("structural requires on type")
+ }
SpecAttributeKind::Ensures => unreachable!("ensures on type"),
+ SpecAttributeKind::PanicEnsures => unreachable!("panic_ensures on type"),
+ SpecAttributeKind::StructuralEnsures => {
+ unreachable!("structural ensures on type")
+ }
+ SpecAttributeKind::StructuralPanicEnsures => {
+ unreachable!("structural panic_ensures on type")
+ }
SpecAttributeKind::AfterExpiry => unreachable!("after_expiry on type"),
SpecAttributeKind::AssertOnExpiry => unreachable!("assert_on_expiry on type"),
SpecAttributeKind::RefineSpec => unreachable!("refine_spec on type"),
SpecAttributeKind::Pure => unreachable!("pure on type"),
SpecAttributeKind::Verified => unreachable!("verified on type"),
+ SpecAttributeKind::NonVerifiedPure => unreachable!("non_verified_pure on type"),
SpecAttributeKind::Invariant => unreachable!("invariant on type"),
SpecAttributeKind::Predicate => unreachable!("predicate on type"),
SpecAttributeKind::Terminates => unreachable!("terminates on type"),
+ SpecAttributeKind::NoPanic => unreachable!("no_panic on type"),
+ SpecAttributeKind::NoPanicEnsuresPostcondition => {
+ unreachable!("no_panic_ensures_postcondition on type")
+ }
+ SpecAttributeKind::NotRequire => {
+ unreachable!("not_require on type")
+ }
+ SpecAttributeKind::NotEnsure => {
+ unreachable!("not_ensure on type")
+ }
SpecAttributeKind::Trusted | SpecAttributeKind::Model => {
assert!(attr.tokens.is_empty(), "Unexpected shape of an attribute.");
attr.tokens
@@ -910,16 +1181,25 @@ fn generate_spec_and_assertions_for_types(
for (attr_kind, attr_tokens) in prusti_attributes.drain(..) {
let rewriting_result = match attr_kind {
SpecAttributeKind::Requires => unreachable!(),
+ SpecAttributeKind::StructuralRequires => unreachable!(),
SpecAttributeKind::Ensures => unreachable!(),
+ SpecAttributeKind::PanicEnsures => unreachable!(),
+ SpecAttributeKind::StructuralEnsures => unreachable!(),
+ SpecAttributeKind::StructuralPanicEnsures => unreachable!(),
SpecAttributeKind::AfterExpiry => unreachable!(),
SpecAttributeKind::AssertOnExpiry => unreachable!(),
SpecAttributeKind::Pure => unreachable!(),
SpecAttributeKind::Verified => unreachable!(),
+ SpecAttributeKind::NonVerifiedPure => unreachable!(),
SpecAttributeKind::Predicate => unreachable!(),
SpecAttributeKind::Invariant => unreachable!(),
SpecAttributeKind::RefineSpec => unreachable!(),
SpecAttributeKind::Terminates => unreachable!(),
SpecAttributeKind::Trusted => generate_for_trusted_for_types(attr_tokens, item),
+ SpecAttributeKind::NoPanic => unreachable!(),
+ SpecAttributeKind::NoPanicEnsuresPostcondition => unreachable!(),
+ SpecAttributeKind::NotRequire => unreachable!(),
+ SpecAttributeKind::NotEnsure => unreachable!(),
SpecAttributeKind::Model => generate_for_model(attr_tokens, item),
SpecAttributeKind::PrintCounterexample => {
generate_for_print_counterexample(attr_tokens, item)
@@ -1013,11 +1293,23 @@ pub fn print_counterexample(attr: TokenStream, tokens: TokenStream) -> TokenStre
.to_compile_error()
}
}
-pub fn ghost(tokens: TokenStream) -> TokenStream {
- let mut rewriter = rewriter::AstRewriter::new();
+
+fn ghost_with_annotation(
+ tokens: TokenStream,
+ annotation: TokenStream,
+ wrap_result_in_ghost: bool,
+ begin_marker: TokenStream,
+ end_marker: TokenStream,
+ spec_id: Option,
+) -> TokenStream {
let callsite_span = Span::call_site();
- let spec_id = rewriter.generate_spec_id();
+ let spec_id = if let Some(spec_id) = spec_id {
+ spec_id
+ } else {
+ let mut rewriter = rewriter::AstRewriter::new();
+ rewriter.generate_spec_id()
+ };
let spec_id_str = spec_id.to_string();
let make_closure = |kind| {
@@ -1106,15 +1398,21 @@ pub fn ghost(tokens: TokenStream) -> TokenStream {
exit_errors.push(*break_span);
}
- let begin = make_closure(quote! {ghost_begin});
- let end = make_closure(quote! {ghost_end});
+ let begin = make_closure(begin_marker);
+ let end = make_closure(end_marker);
+ let ghost_result = if wrap_result_in_ghost {
+ quote! {Ghost::new(#tokens)}
+ } else {
+ quote! {#tokens}
+ };
if exit_errors.is_empty() {
quote_spanned! {callsite_span=>
{
#begin
+ #annotation
#[prusti::specs_version = #SPECS_VERSION]
- let ghost_result = Ghost::new(#tokens);
+ let ghost_result = #ghost_result;
#end
ghost_result
}
@@ -1132,3 +1430,643 @@ pub fn ghost(tokens: TokenStream) -> TokenStream {
syn_errors
}
}
+
+pub fn ghost(tokens: TokenStream) -> TokenStream {
+ ghost_with_annotation(
+ tokens,
+ quote! {},
+ true,
+ quote! {ghost_begin},
+ quote! {ghost_end},
+ None,
+ )
+}
+
+macro_rules! parse_expressions {
+ ($tokens: expr, $separator: ty => $( $expr:ident ),* ) => {
+ let parser = syn::punctuated::Punctuated::::parse_terminated;
+ let expressions = handle_result!(syn::parse::Parser::parse2(parser, $tokens));
+ let mut expressions: Vec<_> = expressions.into_pairs().map(|pair| pair.into_value()).collect();
+ expressions.reverse();
+ $(
+ let $expr = handle_result!(
+ expressions
+ .pop()
+ .ok_or_else(|| syn::Error::new(Span::call_site(), "Expected more expressions"))
+ );
+ )*
+ }
+}
+
+pub fn on_drop_unwind(tokens: TokenStream) -> TokenStream {
+ let OnDropUnwind {
+ dropped_place,
+ block,
+ } = handle_result!(syn::parse2(tokens));
+ ghost_with_annotation(
+ quote! { #block },
+ unsafe_spec_function_call(quote! {
+ prusti_on_drop_unwind(std::ptr::addr_of!(#dropped_place))
+ }),
+ false,
+ quote! {specification_region_begin},
+ quote! {specification_region_end},
+ None,
+ )
+}
+
+pub fn before_drop(tokens: TokenStream) -> TokenStream {
+ let OnDropUnwind {
+ dropped_place,
+ block,
+ } = handle_result!(syn::parse2(tokens));
+ ghost_with_annotation(
+ quote! { #block },
+ unsafe_spec_function_call(quote! {
+ prusti_before_drop(std::ptr::addr_of!(#dropped_place))
+ }),
+ false,
+ quote! {specification_region_begin},
+ quote! {specification_region_end},
+ None,
+ )
+}
+
+pub fn after_drop(tokens: TokenStream) -> TokenStream {
+ let OnDropUnwind {
+ dropped_place,
+ block,
+ } = handle_result!(syn::parse2(tokens));
+ ghost_with_annotation(
+ quote! { #block },
+ unsafe_spec_function_call(quote! {
+ prusti_after_drop(std::ptr::addr_of!(#dropped_place))
+ }),
+ false,
+ quote! {specification_region_begin},
+ quote! {specification_region_end},
+ None,
+ )
+}
+
+pub fn with_finally(tokens: TokenStream) -> TokenStream {
+ let WithFinally {
+ executed_block,
+ on_panic_block,
+ finally_block_at_panic_start,
+ finally_block_at_resume,
+ } = handle_result!(syn::parse2(tokens));
+ let mut rewriter = rewriter::AstRewriter::new();
+ let on_panic_spec_id = rewriter.generate_spec_id();
+ let on_panic_spec_id_str = on_panic_spec_id.to_string();
+ let finally_at_panic_start_spec_id = rewriter.generate_spec_id();
+ let finally_at_panic_start_spec_id_str = finally_at_panic_start_spec_id.to_string();
+ let finally_at_resume_spec_id = rewriter.generate_spec_id();
+ let finally_at_resume_spec_id_str = finally_at_resume_spec_id.to_string();
+ let make_closure = |kind| {
+ quote! {
+ #[allow(unused_must_use, unused_variables, unused_braces, unused_parens)]
+ if false {
+ #[prusti::spec_only]
+ #[prusti::#kind]
+ #[prusti::on_panic_spec_id = #on_panic_spec_id_str]
+ #[prusti::finally_at_panic_start_spec_id = #finally_at_panic_start_spec_id_str]
+ #[prusti::finally_at_resume_spec_id = #finally_at_resume_spec_id_str]
+ || -> () {};
+ }
+ }
+ };
+ let executed_block_begin = make_closure(quote! {try_finally_executed_block_begin});
+ let executed_block_end = make_closure(quote! {try_finally_executed_block_end});
+ let on_panic_ghost_block = ghost_with_annotation(
+ quote! { #on_panic_block },
+ quote! {},
+ false,
+ quote! {specification_region_begin},
+ quote! {specification_region_end},
+ Some(on_panic_spec_id),
+ );
+ let finally_at_panic_start_ghost_block = ghost_with_annotation(
+ quote! { #finally_block_at_panic_start },
+ quote! {},
+ false,
+ quote! {specification_region_begin},
+ quote! {specification_region_end},
+ Some(finally_at_panic_start_spec_id),
+ );
+ let finally_at_resume_ghost_block = ghost_with_annotation(
+ quote! { #finally_block_at_resume },
+ quote! {},
+ false,
+ quote! {specification_region_begin},
+ quote! {specification_region_end},
+ Some(finally_at_resume_spec_id),
+ );
+ quote! {
+ #executed_block_begin
+ #(#executed_block)*
+ #executed_block_end
+ #on_panic_ghost_block
+ #finally_at_panic_start_ghost_block
+ #finally_at_resume_ghost_block
+ }
+}
+
+pub fn checked(tokens: TokenStream) -> TokenStream {
+ let mut rewriter = rewriter::AstRewriter::new();
+ let spec_id = rewriter.generate_spec_id();
+ let spec_id_str = spec_id.to_string();
+ let make_closure = |kind| {
+ quote! {
+ #[allow(unused_must_use, unused_variables, unused_braces, unused_parens)]
+ if false {
+ #[prusti::spec_only]
+ #[prusti::#kind]
+ #[prusti::spec_id = #spec_id_str]
+ || -> () {};
+ }
+ }
+ };
+ let checked_block_begin = make_closure(quote! {checked_block_begin});
+ let checked_block_end = make_closure(quote! {checked_block_end});
+ let tokens = quote! {
+ {
+ #checked_block_begin
+ let result = { #tokens };
+ #checked_block_end
+ result
+ }
+ };
+ tokens
+}
+
+pub fn manually_manage(tokens: TokenStream) -> TokenStream {
+ generate_place_function(tokens, quote! {prusti_manually_manage})
+}
+
+pub fn pack(tokens: TokenStream) -> TokenStream {
+ generate_place_function(tokens, quote! {prusti_pack_place})
+}
+
+pub fn unpack(tokens: TokenStream) -> TokenStream {
+ generate_place_function(tokens, quote! {prusti_unpack_place})
+}
+
+pub fn obtain(tokens: TokenStream) -> TokenStream {
+ generate_place_function(tokens, quote! {prusti_obtain_place})
+}
+
+pub fn pack_ref(tokens: TokenStream) -> TokenStream {
+ // generate_place_function(tokens, quote! {prusti_pack_ref_place})
+ pack_unpack_ref(tokens, quote! {prusti_pack_ref_place})
+}
+
+pub fn unpack_ref(tokens: TokenStream) -> TokenStream {
+ // generate_place_function(tokens, quote! {prusti_unpack_ref_place})
+ pack_unpack_ref(tokens, quote! {prusti_unpack_ref_place})
+}
+
+pub fn pack_mut_ref(tokens: TokenStream) -> TokenStream {
+ // generate_place_function(tokens, quote! {prusti_pack_mut_ref_place})
+ pack_unpack_ref(tokens, quote! {prusti_pack_mut_ref_place})
+}
+
+pub fn unpack_mut_ref(tokens: TokenStream) -> TokenStream {
+ // // generate_place_function(tokens, quote!{prusti_unpack_mut_ref_place})
+ // let (lifetime_name, reference) =
+ // handle_result!(parse_two_expressions::(tokens));
+ // let lifetime_name_str = handle_result!(expression_to_string(&lifetime_name));
+ // unsafe_spec_function_call(quote! {`
+ // prusti_unpack_mut_ref_place(#lifetime_name_str, std::ptr::addr_of!(#reference))
+ // })
+ pack_unpack_ref(tokens, quote! {prusti_unpack_mut_ref_place})
+}
+
+pub fn pack_mut_ref_obligation(tokens: TokenStream) -> TokenStream {
+ // generate_place_function(tokens, quote! {prusti_pack_mut_ref_place})
+ pack_unpack_ref(tokens, quote! {prusti_pack_mut_ref_place_obligation})
+}
+
+pub fn unpack_mut_ref_obligation(tokens: TokenStream) -> TokenStream {
+ pack_unpack_ref(tokens, quote! {prusti_unpack_mut_ref_place_obligation})
+}
+
+fn pack_unpack_ref(tokens: TokenStream, function: TokenStream) -> TokenStream {
+ // let (lifetime_name, reference) =
+ // handle_result!(parse_two_expressions::(tokens));
+ parse_expressions!(tokens, syn::Token![,] => lifetime_name, reference);
+ let lifetime_name_str = handle_result!(expression_to_string(&lifetime_name));
+ unsafe_spec_function_call(quote! {
+ #function(#lifetime_name_str, std::ptr::addr_of!(#reference))
+ })
+}
+
+// fn parse_two_expressions(
+// tokens: TokenStream,
+// ) -> syn::Result<(syn::Expr, syn::Expr)> {
+// // let parser = syn::punctuated::Punctuated::::parse_terminated;
+// // let mut expressions = syn::parse::Parser::parse2(parser, tokens)?;
+// // let second = expressions
+// // .pop()
+// // .ok_or_else(|| syn::Error::new(Span::call_site(), "Expected two expressions"))?;
+// // let first = expressions
+// // .pop()
+// // .ok_or_else(|| syn::Error::new(Span::call_site(), "Expected two expressions"))?;
+// // Ok((first.into_value(), second.into_value()))
+// parse_expressions!(tokens, Separator => first, second);
+// Ok((first, second))
+// }
+
+// fn parse_three_expressions(
+// tokens: TokenStream,
+// ) -> syn::Result<(syn::Expr, syn::Expr, syn::Expr)> {
+// // let parser = syn::punctuated::Punctuated::::parse_terminated;
+// // let mut expressions = syn::parse::Parser::parse2(parser, tokens)?;
+// // let third = expressions
+// // .pop()
+// // .ok_or_else(|| syn::Error::new(Span::call_site(), "Expected three expressions"))?;
+// // let second = expressions
+// // .pop()
+// // .ok_or_else(|| syn::Error::new(Span::call_site(), "Expected three expressions"))?;
+// // let first = expressions
+// // .pop()
+// // .ok_or_else(|| syn::Error::new(Span::call_site(), "Expected three expressions"))?;
+// // Ok((first.into_value(), second.into_value(), third.into_value()))
+// parse_expressions!(tokens, Separator => first, second, third);
+// Ok((first, second, third))
+// }
+
+// fn parse_four_expressions(
+// tokens: TokenStream,
+// ) -> syn::Result<(syn::Expr, syn::Expr, syn::Expr, syn::Expr)> {
+// // let parser = syn::punctuated::Punctuated::::parse_terminated;
+// // let mut expressions = syn::parse::Parser::parse2(parser, tokens)?;
+// // let fourth = expressions
+// // .pop()
+// // .ok_or_else(|| syn::Error::new(Span::call_site(), "Expected four expressions"))?;
+// // let third = expressions
+// // .pop()
+// // .ok_or_else(|| syn::Error::new(Span::call_site(), "Expected four expressions"))?;
+// // let second = expressions
+// // .pop()
+// // .ok_or_else(|| syn::Error::new(Span::call_site(), "Expected four expressions"))?;
+// // let first = expressions
+// // .pop()
+// // .ok_or_else(|| syn::Error::new(Span::call_site(), "Expected four expressions"))?;
+// // Ok((
+// // first.into_value(),
+// // second.into_value(),
+// // third.into_value(),
+// // fourth.into_value(),
+// // ))
+// parse_expressions!(tokens, Separator => first, second, third, fourth);
+// Ok((first, second, third, fourth))
+// }
+
+fn expression_to_string(expr: &syn::Expr) -> syn::Result {
+ if let syn::Expr::Path(syn::ExprPath {
+ qself: None, path, ..
+ }) = expr
+ {
+ if let Some(ident) = path.get_ident() {
+ return Ok(ident.to_string());
+ }
+ }
+ Err(syn::Error::new(expr.span(), "needs to be an identifier"))
+}
+
+pub fn unsafe_spec_function_call(call: TokenStream) -> TokenStream {
+ let callsite_span = Span::call_site();
+ quote_spanned! { callsite_span =>
+ #[allow(unused_must_use, unused_variables)]
+ #[prusti::specs_version = #SPECS_VERSION]
+ if false {
+ #[prusti::spec_only]
+ || -> bool { true };
+ unsafe { #call };
+ }
+ }
+}
+
+pub fn take_lifetime(tokens: TokenStream) -> TokenStream {
+ parse_expressions!(tokens, syn::Token![,] => reference, lifetime_name);
+ // let (reference, lifetime_name) =
+ // handle_result!(parse_two_expressions::(tokens));
+ let lifetime_name_str = handle_result!(expression_to_string(&lifetime_name));
+ unsafe_spec_function_call(quote! {
+ prusti_take_lifetime(std::ptr::addr_of!(#reference), #lifetime_name_str)
+ })
+ // let parser = syn::punctuated::Punctuated::]>::parse_terminated;
+ // let mut args = handle_result!(syn::parse::Parser::parse2(parser, tokens));
+ // let lifetime = if let Some(lifetime) = args.pop() {
+ // lifetime.into_value()
+ // } else {
+ // return syn::Error::new(
+ // args.span(),
+ // "`take_lifetime!` needs to contain two arguments `` and ``"
+ // ).to_compile_error();
+ // };
+ // let lifetime_str = if let syn::Expr::Path(syn::ExprPath { qself: None, path, ..}) = lifetime {
+ // if let Some(ident) = path.get_ident() {
+ // ident.to_string()
+ // } else {
+ // return syn::Error::new(
+ // path.span(),
+ // "lifetime name needs to be an identifier"
+ // ).to_compile_error();
+ // }
+ // } else {
+ // return syn::Error::new(
+ // lifetime.span(),
+ // "lifetime name needs to be an identifier"
+ // ).to_compile_error();
+ // };
+ // let reference = if let Some(reference) = args.pop() {
+ // reference.into_value()
+ // } else {
+ // return syn::Error::new(
+ // args.span(),
+ // "`take_lifetime!` needs to contain two arguments `` and ``"
+ // ).to_compile_error();
+ // };
+ // let callsite_span = Span::call_site();
+ // quote_spanned! { callsite_span =>
+ // #[allow(unused_must_use, unused_variables)]
+ // #[prusti::specs_version = #SPECS_VERSION]
+ // if false {
+ // #[prusti::spec_only]
+ // || -> bool { true };
+ // unsafe { prusti_take_lifetime(std::ptr::addr_of!(#reference), #lifetime_str) };
+ // }
+ // }
+}
+
+pub fn end_loan(tokens: TokenStream) -> TokenStream {
+ parse_expressions!(tokens, syn::Token![,] => lifetime_name);
+ let lifetime_name_str = handle_result!(expression_to_string(&lifetime_name));
+ unsafe_spec_function_call(quote! {
+ prusti_end_loan(#lifetime_name_str)
+ })
+}
+
+pub fn set_lifetime_for_raw_pointer_reference_casts(tokens: TokenStream) -> TokenStream {
+ unsafe_spec_function_call(quote! {
+ prusti_set_lifetime_for_raw_pointer_reference_casts(std::ptr::addr_of!(#tokens))
+ })
+}
+
+pub fn attach_drop_lifetime(tokens: TokenStream) -> TokenStream {
+ parse_expressions!(tokens, syn::Token![,] => drop, reference);
+ unsafe_spec_function_call(quote! {
+ prusti_attach_drop_lifetime(std::ptr::addr_of!(#drop), std::ptr::addr_of!(#reference))
+ })
+}
+
+pub fn join(tokens: TokenStream) -> TokenStream {
+ generate_place_function(tokens, quote! {prusti_join_place})
+}
+
+pub fn join_range(tokens: TokenStream) -> TokenStream {
+ parse_expressions!(tokens, syn::Token![,] => pointer, start_index, end_index);
+ // let (pointer, start_index, end_index) =
+ // handle_result!(parse_three_expressions::(tokens));
+ unsafe_spec_function_call(quote! {
+ prusti_join_range(std::ptr::addr_of!(#pointer), {#start_index}, #end_index)
+ })
+}
+
+pub fn split(tokens: TokenStream) -> TokenStream {
+ generate_place_function(tokens, quote! {prusti_split_place})
+}
+
+pub fn split_range(tokens: TokenStream) -> TokenStream {
+ parse_expressions!(tokens, syn::Token![,] => pointer, start_index, end_index);
+ // let (pointer, start_index, end_index) =
+ // handle_result!(parse_three_expressions::(tokens));
+ unsafe_spec_function_call(quote! {
+ prusti_split_range(std::ptr::addr_of!(#pointer), {#start_index}, #end_index)
+ })
+}
+
+/// FIXME: For `start_index` and `end_index`, we should do the same as for
+/// `body_invariant!`.
+pub fn stash_range(tokens: TokenStream) -> TokenStream {
+ parse_expressions!(tokens, syn::Token![,] => pointer, start_index, end_index, witness);
+ // let (pointer, start_index, end_index, witness) =
+ // handle_result!(parse_four_expressions::(tokens));
+ let witness_str = handle_result!(expression_to_string(&witness));
+ unsafe_spec_function_call(quote! {
+ prusti_stash_range(
+ std::ptr::addr_of!(#pointer),
+ {#start_index},
+ {#end_index},
+ #witness_str
+ )
+ })
+}
+
+/// FIXME: For `new_start_index`, we should do the same as for
+/// `body_invariant!`.
+pub fn restore_stash_range(tokens: TokenStream) -> TokenStream {
+ parse_expressions!(tokens, syn::Token![,] => pointer, new_start_index, witness);
+ // let (pointer, new_start_index, witness) =
+ // handle_result!(parse_three_expressions::(tokens));
+ let witness_str = handle_result!(expression_to_string(&witness));
+ unsafe_spec_function_call(quote! {
+ prusti_restore_stash_range(std::ptr::addr_of!(#pointer), {#new_start_index}, #witness_str)
+ })
+}
+
+pub fn materialize_predicate(tokens: TokenStream) -> TokenStream {
+ let (spec_id, predicate_closure) = handle_result!(prusti_specification_expression(tokens));
+ let spec_id_str = spec_id.to_string();
+ let call = unsafe_spec_function_call(quote! { prusti_materialize_predicate(#spec_id_str) });
+ quote! {
+ #call;
+ #predicate_closure
+ }
+}
+
+pub fn quantified_predicate(tokens: TokenStream) -> TokenStream {
+ let (spec_id, predicate_closure) = handle_result!(prusti_specification_expression(tokens));
+ let spec_id_str = spec_id.to_string();
+ let call = unsafe_spec_function_call(quote! { prusti_quantified_predicate(#spec_id_str) });
+ quote! {
+ #call;
+ #predicate_closure
+ }
+}
+
+pub fn assume_allocation_never_fails(tokens: TokenStream) -> TokenStream {
+ if !tokens.is_empty() {
+ return syn::Error::new(
+ tokens.span(),
+ "`assume_allocation_never_fails` does not take any arguments",
+ )
+ .to_compile_error();
+ }
+ unsafe_spec_function_call(quote! {
+ prusti_assume_allocation_never_fails()
+ })
+}
+
+fn close_any_ref(tokens: TokenStream, function: TokenStream) -> TokenStream {
+ parse_expressions!(tokens, syn::Token![,] => reference, witness);
+ // let (reference, witness) = handle_result!(parse_two_expressions::(tokens));
+ let witness_str = handle_result!(expression_to_string(&witness));
+ let (spec_id, reference_closure) = handle_result!(prusti_specification_expression(
+ quote! { unsafe { reference } }
+ ));
+ let spec_id_str = spec_id.to_string();
+ let call = unsafe_spec_function_call(quote! { #function(#spec_id_str, #witness_str) });
+ quote! {
+ #call;
+ #reference_closure
+ }
+}
+
+pub fn close_ref(tokens: TokenStream) -> TokenStream {
+ close_any_ref(tokens, quote! {prusti_close_ref_place})
+}
+
+pub fn close_mut_ref(tokens: TokenStream) -> TokenStream {
+ close_any_ref(tokens, quote! {prusti_close_mut_ref_place})
+}
+
+fn open_any_ref(tokens: TokenStream, function: TokenStream) -> TokenStream {
+ parse_expressions!(tokens, syn::Token![,] => lifetime_name, reference, witness);
+ // let (lifetime_name, reference, witness) =
+ // handle_result!(parse_three_expressions::(tokens));
+ let lifetime_name_str = handle_result!(expression_to_string(&lifetime_name));
+ let witness_str = handle_result!(expression_to_string(&witness));
+ let (spec_id, reference_closure) = handle_result!(prusti_specification_expression(
+ quote! { unsafe { reference } }
+ ));
+ let spec_id_str = spec_id.to_string();
+ let call = unsafe_spec_function_call(quote! {
+ #function(#lifetime_name_str, #spec_id_str, #witness_str)
+ });
+ quote! {
+ #reference_closure;
+ #call
+ }
+}
+
+pub fn open_ref(tokens: TokenStream) -> TokenStream {
+ open_any_ref(tokens, quote! {prusti_open_ref_place})
+}
+
+pub fn open_mut_ref(tokens: TokenStream) -> TokenStream {
+ open_any_ref(tokens, quote! {prusti_open_mut_ref_place})
+}
+
+pub fn restore_mut_borrowed(tokens: TokenStream) -> TokenStream {
+ parse_expressions!(tokens, syn::Token![,] => referencing_place, referenced_place);
+ let (referencing_place_spec_id, referencing_place_closure) = handle_result!(
+ prusti_specification_expression(quote! { unsafe { referencing_place } })
+ );
+ let (referenced_place_spec_id, referenced_place_closure) = handle_result!(
+ prusti_specification_expression(quote! { unsafe { referenced_place } })
+ );
+ let referencing_place_spec_id_str = referencing_place_spec_id.to_string();
+ let referenced_place_spec_id_str = referenced_place_spec_id.to_string();
+ let call = unsafe_spec_function_call(
+ quote! { prusti_restore_mut_borrowed(#referencing_place_spec_id_str, #referenced_place_spec_id_str) },
+ );
+ quote! {
+ #referencing_place_closure;
+ #call;
+ #referenced_place_closure
+ }
+}
+
+pub fn resolve(tokens: TokenStream) -> TokenStream {
+ generate_place_function(tokens, quote! {prusti_resolve})
+}
+
+pub fn resolve_range(tokens: TokenStream) -> TokenStream {
+ parse_expressions!(tokens, syn::Token![,] =>
+ lifetime_name,
+ pointer,
+ predicate_range_start_index,
+ predicate_range_end_index,
+ start_index,
+ end_index
+ );
+ // let (lifetime_name, pointer, base_index, start_index, end_index) =
+ // handle_result!(parse_five_expressions::