From ce4793bb74c8f58b53525c98b6151158b32d87ac Mon Sep 17 00:00:00 2001 From: AztecBot Date: Wed, 18 Dec 2024 08:08:59 +0000 Subject: [PATCH 1/2] [1 changes] feat: configurable external check failures (https://github.com/noir-lang/noir/pull/6810) chore: move constant creation out of loop (https://github.com/noir-lang/noir/pull/6836) fix: implement `as_field` and `from_field` in the interpreter (https://github.com/noir-lang/noir/pull/6829) chore: Use Vec for callstacks (https://github.com/noir-lang/noir/pull/6821) feat: replace `eval_global_as_array_length` with type/interpreter evaluation (https://github.com/noir-lang/noir/pull/6469) chore: refactor `DataFlowGraph.insert_instruction_and_results` (https://github.com/noir-lang/noir/pull/6823) chore(docs): updating noirjs tutorial for 1.0.0 (https://github.com/noir-lang/noir/pull/6792) feat: Sync from aztec-packages (https://github.com/noir-lang/noir/pull/6824) chore: Have rust-analyzer use the stable toolchain (https://github.com/noir-lang/noir/pull/6825) --- .noir-sync-commit | 2 +- .../noir-projects/aztec-nr.failures.jsonl | 0 .../noir-contracts.failures.jsonl | 0 .../crates/blob.failures.jsonl | 0 .../crates/parity-lib.failures.jsonl | 0 .../crates/private-kernel-lib.failures.jsonl | 0 .../crates/reset-kernel-lib.failures.jsonl | 0 .../crates/rollup-lib.failures.jsonl | 0 .../crates/types.failures.jsonl | 0 .../critical_libraries_status/README.md | 20 + .../noir-lang/ec/.actual.jsonl | 4 + .../noir-lang/ec/.actual.jsonl.jq | 1 + .../noir-lang/ec/.failures.jsonl | 0 .../noir-lang/ec/.failures.jsonl.jq | 0 .../noir-lang/eddsa/.failures.jsonl | 0 .../noir-lang/mimc/.failures.jsonl | 0 .../noir-lang/noir-bignum/.failures.jsonl | 0 .../noir-lang/noir-edwards/.failures.jsonl | 0 .../noir-lang/noir_base64/.failures.jsonl | 0 .../noir-lang/noir_bigcurve/.failures.jsonl | 0 .../noir_json_parser/.failures.jsonl | 0 .../noir-lang/noir_rsa/.failures.jsonl | 0 .../noir-lang/noir_sort/.failures.jsonl | 0 .../noir_string_search/.failures.jsonl | 0 .../noir-lang/schnorr/.failures.jsonl | 0 .../noir-lang/sparse_array/.failures.jsonl | 0 .../.github/scripts/check_test_results.sh | 38 ++ noir/noir-repo/.github/workflows/reports.yml | 46 --- .../.github/workflows/test-js-packages.yml | 17 +- noir/noir-repo/.vscode/settings.json | 3 +- noir/noir-repo/acvm-repo/acvm_js/build.sh | 2 +- .../compiler/integration-tests/package.json | 2 +- .../compiler/noirc_evaluator/src/acir/mod.rs | 4 +- .../compiler/noirc_evaluator/src/errors.rs | 4 +- .../check_for_underconstrained_values.rs | 1 - .../noirc_evaluator/src/ssa/ir/call_stack.rs | 6 +- .../noirc_evaluator/src/ssa/ir/dfg.rs | 56 ++- .../noirc_evaluator/src/ssa/ir/list.rs | 187 --------- .../noirc_evaluator/src/ssa/ir/mod.rs | 1 - .../src/ssa/opt/flatten_cfg.rs | 1 - .../src/ssa/opt/resolve_is_unconstrained.rs | 5 +- .../noirc_frontend/src/ast/statement.rs | 2 + .../noirc_frontend/src/elaborator/mod.rs | 23 +- .../noirc_frontend/src/elaborator/patterns.rs | 4 +- .../src/elaborator/statements.rs | 5 +- .../noirc_frontend/src/elaborator/types.rs | 158 ++------ .../src/hir/comptime/interpreter.rs | 28 +- .../src/hir/comptime/interpreter/builtin.rs | 23 ++ .../noirc_frontend/src/hir/comptime/value.rs | 39 +- .../src/hir/resolution/errors.rs | 43 +- .../src/hir/type_check/errors.rs | 12 - .../noirc_frontend/src/hir_def/stmt.rs | 16 + .../noirc_frontend/src/hir_def/types.rs | 10 +- .../src/monomorphization/mod.rs | 3 +- .../noirc_frontend/src/node_interner.rs | 2 + .../src/parser/parser/global.rs | 5 +- .../src/parser/parser/statement.rs | 9 +- .../compiler/noirc_frontend/src/tests.rs | 93 ++--- .../src/tests/arithmetic_generics.rs | 46 +++ noir/noir-repo/cspell.json | 3 + .../docs/docs/tutorials/noirjs_app.md | 380 ++++++++---------- .../img/tutorials/noirjs_webapp/webapp1.png | Bin 0 -> 15009 bytes .../comptime_as_field/Nargo.toml | 6 + .../comptime_as_field/src/main.nr | 6 + .../comptime_from_field/Nargo.toml | 6 + .../comptime_from_field/src/main.nr | 6 + .../tooling/lsp/src/requests/hover.rs | 28 +- .../nargo_cli/src/cli/test_cmd/formatters.rs | 1 + .../noir-repo/tooling/noirc_abi_wasm/build.sh | 2 +- noir/noir-repo/yarn.lock | 13 +- 70 files changed, 615 insertions(+), 757 deletions(-) create mode 100644 noir/noir-repo/.github/critical_libraries_status/AztecProtocol/aztec-packages/noir-projects/aztec-nr.failures.jsonl create mode 100644 noir/noir-repo/.github/critical_libraries_status/AztecProtocol/aztec-packages/noir-projects/noir-contracts.failures.jsonl create mode 100644 noir/noir-repo/.github/critical_libraries_status/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/blob.failures.jsonl create mode 100644 noir/noir-repo/.github/critical_libraries_status/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/parity-lib.failures.jsonl create mode 100644 noir/noir-repo/.github/critical_libraries_status/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/private-kernel-lib.failures.jsonl create mode 100644 noir/noir-repo/.github/critical_libraries_status/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib.failures.jsonl create mode 100644 noir/noir-repo/.github/critical_libraries_status/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/rollup-lib.failures.jsonl create mode 100644 noir/noir-repo/.github/critical_libraries_status/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/types.failures.jsonl create mode 100644 noir/noir-repo/.github/critical_libraries_status/README.md create mode 100644 noir/noir-repo/.github/critical_libraries_status/noir-lang/ec/.actual.jsonl create mode 100644 noir/noir-repo/.github/critical_libraries_status/noir-lang/ec/.actual.jsonl.jq create mode 100644 noir/noir-repo/.github/critical_libraries_status/noir-lang/ec/.failures.jsonl create mode 100644 noir/noir-repo/.github/critical_libraries_status/noir-lang/ec/.failures.jsonl.jq create mode 100644 noir/noir-repo/.github/critical_libraries_status/noir-lang/eddsa/.failures.jsonl create mode 100644 noir/noir-repo/.github/critical_libraries_status/noir-lang/mimc/.failures.jsonl create mode 100644 noir/noir-repo/.github/critical_libraries_status/noir-lang/noir-bignum/.failures.jsonl create mode 100644 noir/noir-repo/.github/critical_libraries_status/noir-lang/noir-edwards/.failures.jsonl create mode 100644 noir/noir-repo/.github/critical_libraries_status/noir-lang/noir_base64/.failures.jsonl create mode 100644 noir/noir-repo/.github/critical_libraries_status/noir-lang/noir_bigcurve/.failures.jsonl create mode 100644 noir/noir-repo/.github/critical_libraries_status/noir-lang/noir_json_parser/.failures.jsonl create mode 100644 noir/noir-repo/.github/critical_libraries_status/noir-lang/noir_rsa/.failures.jsonl create mode 100644 noir/noir-repo/.github/critical_libraries_status/noir-lang/noir_sort/.failures.jsonl create mode 100644 noir/noir-repo/.github/critical_libraries_status/noir-lang/noir_string_search/.failures.jsonl create mode 100644 noir/noir-repo/.github/critical_libraries_status/noir-lang/schnorr/.failures.jsonl create mode 100644 noir/noir-repo/.github/critical_libraries_status/noir-lang/sparse_array/.failures.jsonl create mode 100755 noir/noir-repo/.github/scripts/check_test_results.sh delete mode 100644 noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/list.rs create mode 100644 noir/noir-repo/docs/static/img/tutorials/noirjs_webapp/webapp1.png create mode 100644 noir/noir-repo/test_programs/compile_success_empty/comptime_as_field/Nargo.toml create mode 100644 noir/noir-repo/test_programs/compile_success_empty/comptime_as_field/src/main.nr create mode 100644 noir/noir-repo/test_programs/compile_success_empty/comptime_from_field/Nargo.toml create mode 100644 noir/noir-repo/test_programs/compile_success_empty/comptime_from_field/src/main.nr diff --git a/.noir-sync-commit b/.noir-sync-commit index a6780a1e9ef..c49f823f0b2 100644 --- a/.noir-sync-commit +++ b/.noir-sync-commit @@ -1 +1 @@ -f337992de96ef656681ebfc96a30c2c9c9b82a70 \ No newline at end of file +73ccd45590222fc82642a6a9aa657c2915fc2c58 diff --git a/noir/noir-repo/.github/critical_libraries_status/AztecProtocol/aztec-packages/noir-projects/aztec-nr.failures.jsonl b/noir/noir-repo/.github/critical_libraries_status/AztecProtocol/aztec-packages/noir-projects/aztec-nr.failures.jsonl new file mode 100644 index 00000000000..e69de29bb2d diff --git a/noir/noir-repo/.github/critical_libraries_status/AztecProtocol/aztec-packages/noir-projects/noir-contracts.failures.jsonl b/noir/noir-repo/.github/critical_libraries_status/AztecProtocol/aztec-packages/noir-projects/noir-contracts.failures.jsonl new file mode 100644 index 00000000000..e69de29bb2d diff --git a/noir/noir-repo/.github/critical_libraries_status/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/blob.failures.jsonl b/noir/noir-repo/.github/critical_libraries_status/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/blob.failures.jsonl new file mode 100644 index 00000000000..e69de29bb2d diff --git a/noir/noir-repo/.github/critical_libraries_status/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/parity-lib.failures.jsonl b/noir/noir-repo/.github/critical_libraries_status/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/parity-lib.failures.jsonl new file mode 100644 index 00000000000..e69de29bb2d diff --git a/noir/noir-repo/.github/critical_libraries_status/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/private-kernel-lib.failures.jsonl b/noir/noir-repo/.github/critical_libraries_status/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/private-kernel-lib.failures.jsonl new file mode 100644 index 00000000000..e69de29bb2d diff --git a/noir/noir-repo/.github/critical_libraries_status/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib.failures.jsonl b/noir/noir-repo/.github/critical_libraries_status/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib.failures.jsonl new file mode 100644 index 00000000000..e69de29bb2d diff --git a/noir/noir-repo/.github/critical_libraries_status/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/rollup-lib.failures.jsonl b/noir/noir-repo/.github/critical_libraries_status/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/rollup-lib.failures.jsonl new file mode 100644 index 00000000000..e69de29bb2d diff --git a/noir/noir-repo/.github/critical_libraries_status/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/types.failures.jsonl b/noir/noir-repo/.github/critical_libraries_status/AztecProtocol/aztec-packages/noir-projects/noir-protocol-circuits/crates/types.failures.jsonl new file mode 100644 index 00000000000..e69de29bb2d diff --git a/noir/noir-repo/.github/critical_libraries_status/README.md b/noir/noir-repo/.github/critical_libraries_status/README.md new file mode 100644 index 00000000000..47e9d7ad6ed --- /dev/null +++ b/noir/noir-repo/.github/critical_libraries_status/README.md @@ -0,0 +1,20 @@ +# Critical Libraries Status + +This directory contains one `.failures.jsonl` file per external directory that is checked by CI. +CI will run the external repository tests and compare the test failures against those recorded +in these files. If there's a difference, CI will fail. + +This allows us to mark some tests as expected to fail if we introduce breaking changes. +When tests are fixed on the external repository, CI will let us know that we need to remove +the `.failures.jsonl` failures on our side. + +The format of the `.failures.jsonl` files is one JSON per line with a failure: + +```json +{"suite":"one","name":"foo"} +``` + +If it's expected that an external repository doesn't compile (because a PR introduces breaking changes +to, say, the type system) you can remove the `.failures.jsonl` file for that repository and CI +will pass again. Once the repository compiles again, CI will let us know and require us to put +back the `.failures.jsonl` file. \ No newline at end of file diff --git a/noir/noir-repo/.github/critical_libraries_status/noir-lang/ec/.actual.jsonl b/noir/noir-repo/.github/critical_libraries_status/noir-lang/ec/.actual.jsonl new file mode 100644 index 00000000000..cb56f792778 --- /dev/null +++ b/noir/noir-repo/.github/critical_libraries_status/noir-lang/ec/.actual.jsonl @@ -0,0 +1,4 @@ +{"event":"started","name":"one","test_count":1,"type":"suite"} +{"event":"started","name":"foo","suite":"one","type":"test"} +{"event":"failed","exec_time":0.05356625,"name":"foo","suite":"one","type":"test"} +{"event":"ok","failed":0,"ignored":0,"passed":1,"type":"suite"} \ No newline at end of file diff --git a/noir/noir-repo/.github/critical_libraries_status/noir-lang/ec/.actual.jsonl.jq b/noir/noir-repo/.github/critical_libraries_status/noir-lang/ec/.actual.jsonl.jq new file mode 100644 index 00000000000..1123e7e68e4 --- /dev/null +++ b/noir/noir-repo/.github/critical_libraries_status/noir-lang/ec/.actual.jsonl.jq @@ -0,0 +1 @@ +{"suite":"one","name":"foo"} diff --git a/noir/noir-repo/.github/critical_libraries_status/noir-lang/ec/.failures.jsonl b/noir/noir-repo/.github/critical_libraries_status/noir-lang/ec/.failures.jsonl new file mode 100644 index 00000000000..e69de29bb2d diff --git a/noir/noir-repo/.github/critical_libraries_status/noir-lang/ec/.failures.jsonl.jq b/noir/noir-repo/.github/critical_libraries_status/noir-lang/ec/.failures.jsonl.jq new file mode 100644 index 00000000000..e69de29bb2d diff --git a/noir/noir-repo/.github/critical_libraries_status/noir-lang/eddsa/.failures.jsonl b/noir/noir-repo/.github/critical_libraries_status/noir-lang/eddsa/.failures.jsonl new file mode 100644 index 00000000000..e69de29bb2d diff --git a/noir/noir-repo/.github/critical_libraries_status/noir-lang/mimc/.failures.jsonl b/noir/noir-repo/.github/critical_libraries_status/noir-lang/mimc/.failures.jsonl new file mode 100644 index 00000000000..e69de29bb2d diff --git a/noir/noir-repo/.github/critical_libraries_status/noir-lang/noir-bignum/.failures.jsonl b/noir/noir-repo/.github/critical_libraries_status/noir-lang/noir-bignum/.failures.jsonl new file mode 100644 index 00000000000..e69de29bb2d diff --git a/noir/noir-repo/.github/critical_libraries_status/noir-lang/noir-edwards/.failures.jsonl b/noir/noir-repo/.github/critical_libraries_status/noir-lang/noir-edwards/.failures.jsonl new file mode 100644 index 00000000000..e69de29bb2d diff --git a/noir/noir-repo/.github/critical_libraries_status/noir-lang/noir_base64/.failures.jsonl b/noir/noir-repo/.github/critical_libraries_status/noir-lang/noir_base64/.failures.jsonl new file mode 100644 index 00000000000..e69de29bb2d diff --git a/noir/noir-repo/.github/critical_libraries_status/noir-lang/noir_bigcurve/.failures.jsonl b/noir/noir-repo/.github/critical_libraries_status/noir-lang/noir_bigcurve/.failures.jsonl new file mode 100644 index 00000000000..e69de29bb2d diff --git a/noir/noir-repo/.github/critical_libraries_status/noir-lang/noir_json_parser/.failures.jsonl b/noir/noir-repo/.github/critical_libraries_status/noir-lang/noir_json_parser/.failures.jsonl new file mode 100644 index 00000000000..e69de29bb2d diff --git a/noir/noir-repo/.github/critical_libraries_status/noir-lang/noir_rsa/.failures.jsonl b/noir/noir-repo/.github/critical_libraries_status/noir-lang/noir_rsa/.failures.jsonl new file mode 100644 index 00000000000..e69de29bb2d diff --git a/noir/noir-repo/.github/critical_libraries_status/noir-lang/noir_sort/.failures.jsonl b/noir/noir-repo/.github/critical_libraries_status/noir-lang/noir_sort/.failures.jsonl new file mode 100644 index 00000000000..e69de29bb2d diff --git a/noir/noir-repo/.github/critical_libraries_status/noir-lang/noir_string_search/.failures.jsonl b/noir/noir-repo/.github/critical_libraries_status/noir-lang/noir_string_search/.failures.jsonl new file mode 100644 index 00000000000..e69de29bb2d diff --git a/noir/noir-repo/.github/critical_libraries_status/noir-lang/schnorr/.failures.jsonl b/noir/noir-repo/.github/critical_libraries_status/noir-lang/schnorr/.failures.jsonl new file mode 100644 index 00000000000..e69de29bb2d diff --git a/noir/noir-repo/.github/critical_libraries_status/noir-lang/sparse_array/.failures.jsonl b/noir/noir-repo/.github/critical_libraries_status/noir-lang/sparse_array/.failures.jsonl new file mode 100644 index 00000000000..e69de29bb2d diff --git a/noir/noir-repo/.github/scripts/check_test_results.sh b/noir/noir-repo/.github/scripts/check_test_results.sh new file mode 100755 index 00000000000..c844c025876 --- /dev/null +++ b/noir/noir-repo/.github/scripts/check_test_results.sh @@ -0,0 +1,38 @@ +#!/bin/bash +set -eu + +# Usage: ./check_test_results.sh +# Compares the output of two test results of the same repository. +# If any of the files doesn't exist or is empty, the script will consider that the test suite +# couldn't be compiled. + +function process_json_lines() { + cat $1 | jq -c 'select(.type == "test" and .event == "failed") | {suite: .suite, name: .name}' | jq -s -c 'sort_by(.suite, .name) | .[]' > $1.jq +} + +if [ -f $1 ] && [ -f $2 ]; then + # Both files exist, let's compare them + $(process_json_lines $2) + if ! diff $1 $2.jq; then + echo "Error: test failures don't match expected failures" + echo "Lines prefixed with '>' are new test failures (you could add them to '$1')" + echo "Lines prefixed with '<' are tests that were expected to fail but passed (you could remove them from '$1')" + fi +elif [ -f $1 ]; then + # Only the expected file exists, which means the actual test couldn't be compiled. + echo "Error: external library tests couldn't be compiled." + echo "You could rename '$1' to '$1.does_not_compile' if it's expected that the external library can't be compiled." + exit -1 +elif [ -f $2 ]; then + # Only the actual file exists, which means we are expecting the external library + # not to compile but it did. + echo "Error: expected external library not to compile, but it did." + echo "You could create '$1' with these contents:" + $(process_json_lines $2) + cat $2.jq + exit -1 +else + # Both files don't exists, which means we are expecting the external library not + # to compile, and it didn't, so all is good. + exit 0 +fi \ No newline at end of file diff --git a/noir/noir-repo/.github/workflows/reports.yml b/noir/noir-repo/.github/workflows/reports.yml index 1e355dc9e6b..0a03add8338 100644 --- a/noir/noir-repo/.github/workflows/reports.yml +++ b/noir/noir-repo/.github/workflows/reports.yml @@ -490,49 +490,3 @@ jobs: with: header: memory message: ${{ steps.memory_report.outputs.markdown }} - - generate_compilation_report: - name: Compilation time - needs: [build-nargo] - runs-on: ubuntu-22.04 - permissions: - pull-requests: write - - steps: - - uses: actions/checkout@v4 - - - name: Download nargo binary - uses: actions/download-artifact@v4 - with: - name: nargo - path: ./nargo - - - name: Set nargo on PATH - run: | - nargo_binary="${{ github.workspace }}/nargo/nargo" - chmod +x $nargo_binary - echo "$(dirname $nargo_binary)" >> $GITHUB_PATH - export PATH="$PATH:$(dirname $nargo_binary)" - nargo -V - - - name: Generate Compilation report - working-directory: ./test_programs - run: | - ./compilation_report.sh - mv compilation_report.json ../compilation_report.json - - - name: Parse compilation report - id: compilation_report - uses: noir-lang/noir-bench-report@0d7464a8c39170523932d7846b6e6b458a294aea - with: - report: compilation_report.json - header: | - # Compilation Report - memory_report: false - - - name: Add memory report to sticky comment - if: github.event_name == 'pull_request' || github.event_name == 'pull_request_target' - uses: marocchino/sticky-pull-request-comment@v2 - with: - header: compilation - message: ${{ steps.compilation_report.outputs.markdown }} diff --git a/noir/noir-repo/.github/workflows/test-js-packages.yml b/noir/noir-repo/.github/workflows/test-js-packages.yml index d227b4eb00b..e593389a971 100644 --- a/noir/noir-repo/.github/workflows/test-js-packages.yml +++ b/noir/noir-repo/.github/workflows/test-js-packages.yml @@ -543,8 +543,6 @@ jobs: external-repo-checks: needs: [build-nargo, critical-library-list] runs-on: ubuntu-22.04 - # Only run when 'run-external-checks' label is present - if: contains(github.event.pull_request.labels.*.name, 'run-external-checks') timeout-minutes: 30 strategy: fail-fast: false @@ -557,11 +555,17 @@ jobs: - project: { repo: AztecProtocol/aztec-packages, path: noir-projects/noir-protocol-circuits/crates/parity-lib } - project: { repo: AztecProtocol/aztec-packages, path: noir-projects/noir-protocol-circuits/crates/private-kernel-lib } - project: { repo: AztecProtocol/aztec-packages, path: noir-projects/noir-protocol-circuits/crates/reset-kernel-lib } - - project: { repo: AztecProtocol/aztec-packages, path: noir-projects/noir-protocol-circuits/crates/rollup-lib } - project: { repo: AztecProtocol/aztec-packages, path: noir-projects/noir-protocol-circuits/crates/types } + # Use 1 test threads for rollup-lib because each test requires a lot of memory, and multiple ones in parallel exceed the maximum memory limit. + - project: { repo: AztecProtocol/aztec-packages, path: noir-projects/noir-protocol-circuits/crates/rollup-lib, nargo_args: "--test-threads 1" } name: Check external repo - ${{ matrix.project.repo }}/${{ matrix.project.path }} steps: + - name: Checkout + uses: actions/checkout@v4 + with: + path: noir-repo + - name: Checkout uses: actions/checkout@v4 with: @@ -592,9 +596,14 @@ jobs: - name: Run nargo test working-directory: ./test-repo/${{ matrix.project.path }} - run: nargo test -q --silence-warnings + run: | + out=$(nargo test --silence-warnings --skip-brillig-constraints-check --format json ${{ matrix.project.nargo_args }}) && echo "$out" > ${{ github.workspace }}/noir-repo/.github/critical_libraries_status/${{ matrix.project.repo }}/${{ matrix.project.path }}.actual.jsonl env: NARGO_IGNORE_TEST_FAILURES_FROM_FOREIGN_CALLS: true + + - name: Compare test results + working-directory: ./noir-repo + run: .github/scripts/check_test_results.sh .github/critical_libraries_status/${{ matrix.project.repo }}/${{ matrix.project.path }}.failures.jsonl .github/critical_libraries_status/${{ matrix.project.repo }}/${{ matrix.project.path }}.actual.jsonl # This is a job which depends on all test jobs and reports the overall status. # This allows us to add/remove test jobs without having to update the required workflows. diff --git a/noir/noir-repo/.vscode/settings.json b/noir/noir-repo/.vscode/settings.json index fb8ea527881..cd1c5f886df 100644 --- a/noir/noir-repo/.vscode/settings.json +++ b/noir/noir-repo/.vscode/settings.json @@ -7,5 +7,6 @@ }, "[javascript]": { "editor.defaultFormatter": "esbenp.prettier-vscode" - } + }, + "rust-analyzer.server.extraEnv": { "RUSTUP_TOOLCHAIN": "stable" } } diff --git a/noir/noir-repo/acvm-repo/acvm_js/build.sh b/noir/noir-repo/acvm-repo/acvm_js/build.sh index c07d2d8a4c1..16fb26e55db 100755 --- a/noir/noir-repo/acvm-repo/acvm_js/build.sh +++ b/noir/noir-repo/acvm-repo/acvm_js/build.sh @@ -25,7 +25,7 @@ function run_if_available { require_command jq require_command cargo require_command wasm-bindgen -#require_command wasm-opt +require_command wasm-opt self_path=$(dirname "$(readlink -f "$0")") pname=$(cargo read-manifest | jq -r '.name') diff --git a/noir/noir-repo/compiler/integration-tests/package.json b/noir/noir-repo/compiler/integration-tests/package.json index e33179f31e7..bfaa1cabd16 100644 --- a/noir/noir-repo/compiler/integration-tests/package.json +++ b/noir/noir-repo/compiler/integration-tests/package.json @@ -13,7 +13,7 @@ "lint": "NODE_NO_WARNINGS=1 eslint . --ext .ts --ignore-path ./.eslintignore --max-warnings 0" }, "dependencies": { - "@aztec/bb.js": "portal:../../../../barretenberg/ts", + "@aztec/bb.js": "0.66.0", "@noir-lang/noir_js": "workspace:*", "@noir-lang/noir_wasm": "workspace:*", "@nomicfoundation/hardhat-chai-matchers": "^2.0.0", diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/acir/mod.rs b/noir/noir-repo/compiler/noirc_evaluator/src/acir/mod.rs index e7b011b6d7b..43eb7df303f 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/acir/mod.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/acir/mod.rs @@ -2905,7 +2905,6 @@ mod test { ssa::{ function_builder::FunctionBuilder, ir::{ - call_stack::CallStack, function::FunctionId, instruction::BinaryOp, map::Id, @@ -2932,8 +2931,7 @@ mod test { builder.new_function("foo".into(), foo_id, inline_type); } // Set a call stack for testing whether `brillig_locations` in the `GeneratedAcir` was accurately set. - let mut stack = CallStack::unit(Location::dummy()); - stack.push_back(Location::dummy()); + let stack = vec![Location::dummy(), Location::dummy()]; let call_stack = builder.current_function.dfg.call_stack_data.get_or_insert_locations(stack); builder.set_call_stack(call_stack); diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/errors.rs b/noir/noir-repo/compiler/noirc_evaluator/src/errors.rs index ee662c50b75..1e484f8af59 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/errors.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/errors.rs @@ -201,7 +201,7 @@ impl RuntimeError { RuntimeError::UnknownLoopBound { .. } => { let primary_message = self.to_string(); let location = - self.call_stack().back().expect("Expected RuntimeError to have a location"); + self.call_stack().last().expect("Expected RuntimeError to have a location"); Diagnostic::simple_error( primary_message, @@ -212,7 +212,7 @@ impl RuntimeError { _ => { let message = self.to_string(); let location = - self.call_stack().back().unwrap_or_else(|| panic!("Expected RuntimeError to have a location. Error message: {message}")); + self.call_stack().last().unwrap_or_else(|| panic!("Expected RuntimeError to have a location. Error message: {message}")); Diagnostic::simple_error(message, String::new(), location.span) } diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/checks/check_for_underconstrained_values.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/checks/check_for_underconstrained_values.rs index 48be8eb7ad8..01d1d51c730 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/checks/check_for_underconstrained_values.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/checks/check_for_underconstrained_values.rs @@ -319,7 +319,6 @@ impl DependencyContext { Value::Function(callee) => match all_functions[&callee].runtime() { RuntimeType::Brillig(_) => { // Record arguments/results for each Brillig call for the check - self.tainted.insert( *instruction, BrilligTaintedIds::new(&arguments, &results), diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/call_stack.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/call_stack.rs index 113609f4a11..e1df616bc66 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/call_stack.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/call_stack.rs @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize}; use noirc_errors::Location; -pub(crate) type CallStack = im::Vector; +pub(crate) type CallStack = Vec; #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] pub(crate) struct CallStackId(u32); @@ -57,9 +57,9 @@ impl Default for CallStackHelper { impl CallStackHelper { /// Construct a CallStack from a CallStackId pub(crate) fn get_call_stack(&self, mut call_stack: CallStackId) -> CallStack { - let mut result = im::Vector::new(); + let mut result = Vec::new(); while let Some(parent) = self.locations[call_stack.index()].parent { - result.push_back(self.locations[call_stack.index()].value); + result.push(self.locations[call_stack.index()].value); call_stack = parent; } result diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/dfg.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/dfg.rs index 72ba369f98c..27eeaa0e15b 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/dfg.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/dfg.rs @@ -165,6 +165,36 @@ impl DataFlowGraph { id } + fn insert_instruction_without_simplification( + &mut self, + instruction_data: Instruction, + block: BasicBlockId, + ctrl_typevars: Option>, + call_stack: CallStackId, + ) -> InstructionId { + let id = self.make_instruction(instruction_data, ctrl_typevars); + self.blocks[block].insert_instruction(id); + self.locations.insert(id, call_stack); + id + } + + pub(crate) fn insert_instruction_and_results_without_simplification( + &mut self, + instruction_data: Instruction, + block: BasicBlockId, + ctrl_typevars: Option>, + call_stack: CallStackId, + ) -> InsertInstructionResult { + let id = self.insert_instruction_without_simplification( + instruction_data, + block, + ctrl_typevars, + call_stack, + ); + + InsertInstructionResult::Results(id, self.instruction_results(id)) + } + /// Inserts a new instruction at the end of the given block and returns its results pub(crate) fn insert_instruction_and_results( &mut self, @@ -184,7 +214,8 @@ impl DataFlowGraph { result @ (SimplifyResult::SimplifiedToInstruction(_) | SimplifyResult::SimplifiedToInstructionMultiple(_) | SimplifyResult::None) => { - let instructions = result.instructions().unwrap_or(vec![instruction]); + let mut instructions = result.instructions().unwrap_or(vec![instruction]); + assert!(!instructions.is_empty(), "`SimplifyResult::SimplifiedToInstructionMultiple` must not return empty vector"); if instructions.len() > 1 { // There's currently no way to pass results from one instruction in `instructions` on to the next. @@ -196,17 +227,22 @@ impl DataFlowGraph { ); } - let mut last_id = None; - + // Pull off the last instruction as we want to return its results. + let last_instruction = instructions.pop().expect("`instructions` can't be empty"); for instruction in instructions { - let id = self.make_instruction(instruction, ctrl_typevars.clone()); - self.blocks[block].insert_instruction(id); - self.locations.insert(id, call_stack); - last_id = Some(id); + self.insert_instruction_without_simplification( + instruction, + block, + ctrl_typevars.clone(), + call_stack, + ); } - - let id = last_id.expect("There should be at least 1 simplified instruction"); - InsertInstructionResult::Results(id, self.instruction_results(id)) + self.insert_instruction_and_results_without_simplification( + last_instruction, + block, + ctrl_typevars, + call_stack, + ) } } } diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/list.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/list.rs deleted file mode 100644 index 9a84d304444..00000000000 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/list.rs +++ /dev/null @@ -1,187 +0,0 @@ -use serde::{Deserialize, Serialize}; -use std::sync::Arc; - -/// A shared linked list type intended to be cloned -#[derive(Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] -pub struct List { - head: Arc>, - len: usize, -} - -#[derive(Default, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] -enum Node { - #[default] - Nil, - Cons(T, Arc>), -} - -impl Default for List { - fn default() -> Self { - List { head: Arc::new(Node::Nil), len: 0 } - } -} - -impl List { - pub fn new() -> Self { - Self::default() - } - - /// This is actually a push_front since we just create a new head for the - /// list. This is done so that the tail of the list can still be shared. - /// In the case of call stacks, the last node will be main, while the top - /// of the call stack will be the head of this list. - pub fn push_back(&mut self, value: T) { - self.len += 1; - self.head = Arc::new(Node::Cons(value, self.head.clone())); - } - - /// It is more efficient to iterate from the head of the list towards the tail. - /// For callstacks this means from the top of the call stack towards main. - fn iter_rev(&self) -> IterRev { - IterRev { head: &self.head, len: self.len } - } - - pub fn clear(&mut self) { - *self = Self::default(); - } - - pub fn append(&mut self, other: Self) - where - T: Copy + std::fmt::Debug, - { - let other = other.into_iter().collect::>(); - - for item in other { - self.push_back(item); - } - } - - pub fn len(&self) -> usize { - self.len - } - - pub fn is_empty(&self) -> bool { - self.len == 0 - } - - fn pop_front(&mut self) -> Option - where - T: Copy, - { - match self.head.as_ref() { - Node::Nil => None, - Node::Cons(value, rest) => { - let value = *value; - self.head = rest.clone(); - self.len -= 1; - Some(value) - } - } - } - - pub fn truncate(&mut self, len: usize) - where - T: Copy, - { - if self.len > len { - for _ in 0..self.len - len { - self.pop_front(); - } - } - } - - pub fn unit(item: T) -> Self { - let mut this = Self::default(); - this.push_back(item); - this - } - - pub fn back(&self) -> Option<&T> { - match self.head.as_ref() { - Node::Nil => None, - Node::Cons(item, _) => Some(item), - } - } -} - -pub struct IterRev<'a, T> { - head: &'a Node, - len: usize, -} - -impl IntoIterator for List -where - T: Copy + std::fmt::Debug, -{ - type Item = T; - - type IntoIter = std::iter::Rev>; - - fn into_iter(self) -> Self::IntoIter { - let items: Vec<_> = self.iter_rev().copied().collect(); - items.into_iter().rev() - } -} - -impl<'a, T> IntoIterator for &'a List { - type Item = &'a T; - - type IntoIter = std::iter::Rev< as IntoIterator>::IntoIter>; - - fn into_iter(self) -> Self::IntoIter { - let items: Vec<_> = self.iter_rev().collect(); - items.into_iter().rev() - } -} - -impl<'a, T> Iterator for IterRev<'a, T> { - type Item = &'a T; - - fn next(&mut self) -> Option { - match self.head { - Node::Nil => None, - Node::Cons(value, rest) => { - self.head = rest; - Some(value) - } - } - } - - fn size_hint(&self) -> (usize, Option) { - (0, Some(self.len)) - } -} - -impl<'a, T> ExactSizeIterator for IterRev<'a, T> {} - -impl std::fmt::Debug for List -where - T: std::fmt::Debug, -{ - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "[")?; - for (i, item) in self.iter_rev().enumerate() { - if i != 0 { - write!(f, ", ")?; - } - write!(f, "{item:?}")?; - } - write!(f, "]") - } -} - -impl std::fmt::Display for List -where - T: std::fmt::Display, -{ - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "[")?; - for (i, item) in self.iter_rev().enumerate() { - if i != 0 { - write!(f, ", ")?; - } - write!(f, "{item}")?; - } - write!(f, "]") - } -} diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/mod.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/mod.rs index 88e0d8900db..686606452fb 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/mod.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/mod.rs @@ -6,7 +6,6 @@ pub(crate) mod dom; pub(crate) mod function; pub(crate) mod function_inserter; pub(crate) mod instruction; -pub mod list; pub(crate) mod map; pub(crate) mod post_order; pub(crate) mod printer; diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs index 43420229257..9b9d0daf3ec 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs @@ -706,7 +706,6 @@ impl<'f> Context<'f> { let argument_type = self.inserter.function.dfg.type_of_value(field); let cast = Instruction::Cast(condition, argument_type.unwrap_numeric()); - let casted_condition = self.insert_instruction(cast, call_stack); let field = self.insert_instruction( Instruction::binary(BinaryOp::Mul, field, casted_condition), diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/resolve_is_unconstrained.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/resolve_is_unconstrained.rs index 87e680932c6..eff6576b87f 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/resolve_is_unconstrained.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/resolve_is_unconstrained.rs @@ -39,6 +39,8 @@ impl Function { } } + let is_unconstrained = matches!(self.runtime(), RuntimeType::Brillig(_)).into(); + let is_within_unconstrained = self.dfg.make_constant(is_unconstrained, NumericType::bool()); for instruction_id in is_unconstrained_calls { let call_returns = self.dfg.instruction_results(instruction_id); let original_return_id = call_returns[0]; @@ -46,9 +48,6 @@ impl Function { // We replace the result with a fresh id. This will be unused, so the DIE pass will remove the leftover intrinsic call. self.dfg.replace_result(instruction_id, original_return_id); - let is_unconstrained = matches!(self.runtime(), RuntimeType::Brillig(_)).into(); - let is_within_unconstrained = - self.dfg.make_constant(is_unconstrained, NumericType::bool()); // Replace all uses of the original return value with the constant self.dfg.set_value_from_id(original_return_id, is_within_unconstrained); } diff --git a/noir/noir-repo/compiler/noirc_frontend/src/ast/statement.rs b/noir/noir-repo/compiler/noirc_frontend/src/ast/statement.rs index c77fe7513a1..0ce21f9f798 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/ast/statement.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/ast/statement.rs @@ -154,6 +154,7 @@ impl StatementKind { r#type, expression, comptime: false, + is_global_let: false, attributes, }) } @@ -562,6 +563,7 @@ pub struct LetStatement { // True if this should only be run during compile-time pub comptime: bool, + pub is_global_let: bool, } #[derive(Debug, PartialEq, Eq, Clone)] diff --git a/noir/noir-repo/compiler/noirc_frontend/src/elaborator/mod.rs b/noir/noir-repo/compiler/noirc_frontend/src/elaborator/mod.rs index fe1d1e38e1a..4a5947f15e3 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/elaborator/mod.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/elaborator/mod.rs @@ -1652,20 +1652,13 @@ impl<'context> Elaborator<'context> { self.push_err(ResolverError::MutableGlobal { span }); } - let comptime = let_stmt.comptime; - - let (let_statement, _typ) = if comptime { - self.elaborate_in_comptime_context(|this| this.elaborate_let(let_stmt, Some(global_id))) - } else { - self.elaborate_let(let_stmt, Some(global_id)) - }; + let (let_statement, _typ) = self + .elaborate_in_comptime_context(|this| this.elaborate_let(let_stmt, Some(global_id))); let statement_id = self.interner.get_global(global_id).let_statement; self.interner.replace_statement(statement_id, let_statement); - if comptime { - self.elaborate_comptime_global(global_id); - } + self.elaborate_comptime_global(global_id); if let Some(name) = name { self.interner.register_global(global_id, name, global.visibility, self.module_id()); @@ -1700,6 +1693,16 @@ impl<'context> Elaborator<'context> { } } + /// If the given global is unresolved, elaborate it and return true + fn elaborate_global_if_unresolved(&mut self, global_id: &GlobalId) -> bool { + if let Some(global) = self.unresolved_globals.remove(global_id) { + self.elaborate_global(global); + true + } else { + false + } + } + fn define_function_metas( &mut self, functions: &mut [UnresolvedFunctions], diff --git a/noir/noir-repo/compiler/noirc_frontend/src/elaborator/patterns.rs b/noir/noir-repo/compiler/noirc_frontend/src/elaborator/patterns.rs index 3fbdadbbee8..0406321de42 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/elaborator/patterns.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/elaborator/patterns.rs @@ -666,9 +666,7 @@ impl<'context> Elaborator<'context> { self.interner.add_function_reference(func_id, hir_ident.location); } DefinitionKind::Global(global_id) => { - if let Some(global) = self.unresolved_globals.remove(&global_id) { - self.elaborate_global(global); - } + self.elaborate_global_if_unresolved(&global_id); if let Some(current_item) = self.current_item { self.interner.add_global_dependency(current_item, global_id); } diff --git a/noir/noir-repo/compiler/noirc_frontend/src/elaborator/statements.rs b/noir/noir-repo/compiler/noirc_frontend/src/elaborator/statements.rs index 93009f49071..8a46d85d563 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/elaborator/statements.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/elaborator/statements.rs @@ -76,6 +76,7 @@ impl<'context> Elaborator<'context> { ) -> (HirStatement, Type) { let expr_span = let_stmt.expression.span; let (expression, expr_type) = self.elaborate_expression(let_stmt.expression); + let type_contains_unspecified = let_stmt.r#type.contains_unspecified(); let annotated_type = self.resolve_inferred_type(let_stmt.r#type); @@ -123,7 +124,9 @@ impl<'context> Elaborator<'context> { let attributes = let_stmt.attributes; let comptime = let_stmt.comptime; - let let_ = HirLetStatement { pattern, r#type, expression, attributes, comptime }; + let is_global_let = let_stmt.is_global_let; + let let_ = + HirLetStatement::new(pattern, r#type, expression, attributes, comptime, is_global_let); (HirStatement::Let(let_), Type::Unit) } diff --git a/noir/noir-repo/compiler/noirc_frontend/src/elaborator/types.rs b/noir/noir-repo/compiler/noirc_frontend/src/elaborator/types.rs index 2e4809f3511..3551edf93f7 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/elaborator/types.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/elaborator/types.rs @@ -1,6 +1,5 @@ use std::{borrow::Cow, rc::Rc}; -use acvm::acir::AcirField; use iter_extended::vecmap; use noirc_errors::{Location, Span}; use rustc_hash::FxHashMap as HashMap; @@ -12,7 +11,6 @@ use crate::{ UnresolvedTypeData, UnresolvedTypeExpression, WILDCARD_TYPE, }, hir::{ - comptime::{Interpreter, Value}, def_collector::dc_crate::CompilationError, resolution::{errors::ResolverError, import::PathResolutionError}, type_check::{ @@ -30,8 +28,8 @@ use crate::{ traits::{NamedType, ResolvedTraitBound, Trait, TraitConstraint}, }, node_interner::{ - DefinitionKind, DependencyId, ExprId, GlobalId, ImplSearchErrorKind, NodeInterner, TraitId, - TraitImplKind, TraitMethodId, + DependencyId, ExprId, ImplSearchErrorKind, NodeInterner, TraitId, TraitImplKind, + TraitMethodId, }, token::SecondaryAttribute, Generics, Kind, ResolvedGeneric, Type, TypeBinding, TypeBindings, UnificationError, @@ -415,17 +413,40 @@ impl<'context> Elaborator<'context> { .map(|let_statement| Kind::numeric(let_statement.r#type)) .unwrap_or(Kind::u32()); - // TODO(https://github.com/noir-lang/noir/issues/6238): - // support non-u32 generics here - if !kind.unifies(&Kind::u32()) { - let error = TypeCheckError::EvaluatedGlobalIsntU32 { - expected_kind: Kind::u32().to_string(), - expr_kind: kind.to_string(), - expr_span: path.span(), - }; - self.push_err(error); - } - Some(Type::Constant(self.eval_global_as_array_length(id, path).into(), kind)) + let Some(stmt) = self.interner.get_global_let_statement(id) else { + if self.elaborate_global_if_unresolved(&id) { + return self.lookup_generic_or_global_type(path); + } else { + let path = path.clone(); + self.push_err(ResolverError::NoSuchNumericTypeVariable { path }); + return None; + } + }; + + let rhs = stmt.expression; + let span = self.interner.expr_span(&rhs); + + let Some(global_value) = &self.interner.get_global(id).value else { + self.push_err(ResolverError::UnevaluatedGlobalType { span }); + return None; + }; + + let Some(global_value) = global_value.to_field_element() else { + let global_value = global_value.clone(); + if global_value.is_integral() { + self.push_err(ResolverError::NegativeGlobalType { span, global_value }); + } else { + self.push_err(ResolverError::NonIntegralGlobalType { span, global_value }); + } + return None; + }; + + let Ok(global_value) = kind.ensure_value_fits(global_value, span) else { + self.push_err(ResolverError::GlobalLargerThanKind { span, global_value, kind }); + return None; + }; + + Some(Type::Constant(global_value, kind)) } _ => None, } @@ -633,31 +654,6 @@ impl<'context> Elaborator<'context> { .or_else(|| self.resolve_trait_method_by_named_generic(path)) } - fn eval_global_as_array_length(&mut self, global_id: GlobalId, path: &Path) -> u32 { - let Some(stmt) = self.interner.get_global_let_statement(global_id) else { - if let Some(global) = self.unresolved_globals.remove(&global_id) { - self.elaborate_global(global); - return self.eval_global_as_array_length(global_id, path); - } else { - let path = path.clone(); - self.push_err(ResolverError::NoSuchNumericTypeVariable { path }); - return 0; - } - }; - - let length = stmt.expression; - let span = self.interner.expr_span(&length); - let result = try_eval_array_length_id(self.interner, length, span); - - match result.map(|length| length.try_into()) { - Ok(Ok(length_value)) => return length_value, - Ok(Err(_cast_err)) => self.push_err(ResolverError::IntegerTooLarge { span }), - Err(Some(error)) => self.push_err(error), - Err(None) => (), - } - 0 - } - pub(super) fn unify( &mut self, actual: &Type, @@ -1834,88 +1830,6 @@ fn bind_generic(param: &ResolvedGeneric, arg: &Type, bindings: &mut TypeBindings } } -pub fn try_eval_array_length_id( - interner: &NodeInterner, - rhs: ExprId, - span: Span, -) -> Result> { - // Arbitrary amount of recursive calls to try before giving up - let fuel = 100; - try_eval_array_length_id_with_fuel(interner, rhs, span, fuel) -} - -fn try_eval_array_length_id_with_fuel( - interner: &NodeInterner, - rhs: ExprId, - span: Span, - fuel: u32, -) -> Result> { - if fuel == 0 { - // If we reach here, it is likely from evaluating cyclic globals. We expect an error to - // be issued for them after name resolution so issue no error now. - return Err(None); - } - - match interner.expression(&rhs) { - HirExpression::Literal(HirLiteral::Integer(int, false)) => { - int.try_into_u128().ok_or(Some(ResolverError::IntegerTooLarge { span })) - } - HirExpression::Ident(ident, _) => { - if let Some(definition) = interner.try_definition(ident.id) { - match definition.kind { - DefinitionKind::Global(global_id) => { - let let_statement = interner.get_global_let_statement(global_id); - if let Some(let_statement) = let_statement { - let expression = let_statement.expression; - try_eval_array_length_id_with_fuel(interner, expression, span, fuel - 1) - } else { - Err(Some(ResolverError::InvalidArrayLengthExpr { span })) - } - } - _ => Err(Some(ResolverError::InvalidArrayLengthExpr { span })), - } - } else { - Err(Some(ResolverError::InvalidArrayLengthExpr { span })) - } - } - HirExpression::Infix(infix) => { - let lhs = try_eval_array_length_id_with_fuel(interner, infix.lhs, span, fuel - 1)?; - let rhs = try_eval_array_length_id_with_fuel(interner, infix.rhs, span, fuel - 1)?; - - match infix.operator.kind { - BinaryOpKind::Add => Ok(lhs + rhs), - BinaryOpKind::Subtract => Ok(lhs - rhs), - BinaryOpKind::Multiply => Ok(lhs * rhs), - BinaryOpKind::Divide => Ok(lhs / rhs), - BinaryOpKind::Equal => Ok((lhs == rhs) as u128), - BinaryOpKind::NotEqual => Ok((lhs != rhs) as u128), - BinaryOpKind::Less => Ok((lhs < rhs) as u128), - BinaryOpKind::LessEqual => Ok((lhs <= rhs) as u128), - BinaryOpKind::Greater => Ok((lhs > rhs) as u128), - BinaryOpKind::GreaterEqual => Ok((lhs >= rhs) as u128), - BinaryOpKind::And => Ok(lhs & rhs), - BinaryOpKind::Or => Ok(lhs | rhs), - BinaryOpKind::Xor => Ok(lhs ^ rhs), - BinaryOpKind::ShiftRight => Ok(lhs >> rhs), - BinaryOpKind::ShiftLeft => Ok(lhs << rhs), - BinaryOpKind::Modulo => Ok(lhs % rhs), - } - } - HirExpression::Cast(cast) => { - let lhs = try_eval_array_length_id_with_fuel(interner, cast.lhs, span, fuel - 1)?; - let lhs_value = Value::Field(lhs.into()); - let evaluated_value = - Interpreter::evaluate_cast_one_step(&cast, rhs, lhs_value, interner) - .map_err(|error| Some(ResolverError::ArrayLengthInterpreter { error }))?; - - evaluated_value - .to_u128() - .ok_or_else(|| Some(ResolverError::InvalidArrayLengthExpr { span })) - } - _other => Err(Some(ResolverError::InvalidArrayLengthExpr { span })), - } -} - /// Gives an error if a user tries to create a mutable reference /// to an immutable variable. fn verify_mutable_reference(interner: &NodeInterner, rhs: ExprId) -> Result<(), ResolverError> { diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/interpreter.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/interpreter.rs index dfa55a9d79b..b6ae4629763 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/interpreter.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/interpreter.rs @@ -581,7 +581,7 @@ impl<'local, 'interner> Interpreter<'local, 'interner> { }, )?; - if let_.comptime || crate_of_global != self.crate_id { + if let_.runs_comptime() || crate_of_global != self.crate_id { self.evaluate_let(let_.clone())?; } @@ -1380,13 +1380,19 @@ impl<'local, 'interner> Interpreter<'local, 'interner> { fn evaluate_cast(&mut self, cast: &HirCastExpression, id: ExprId) -> IResult { let evaluated_lhs = self.evaluate(cast.lhs)?; - Self::evaluate_cast_one_step(cast, id, evaluated_lhs, self.elaborator.interner) + let location = self.elaborator.interner.expr_location(&id); + Self::evaluate_cast_one_step( + &cast.r#type, + location, + evaluated_lhs, + self.elaborator.interner, + ) } /// evaluate_cast without recursion pub fn evaluate_cast_one_step( - cast: &HirCastExpression, - id: ExprId, + typ: &Type, + location: Location, evaluated_lhs: Value, interner: &NodeInterner, ) -> IResult { @@ -1417,7 +1423,6 @@ impl<'local, 'interner> Interpreter<'local, 'interner> { (if value { FieldElement::one() } else { FieldElement::zero() }, false) } value => { - let location = interner.expr_location(&id); let typ = value.get_type().into_owned(); return Err(InterpreterError::NonNumericCasted { typ, location }); } @@ -1434,7 +1439,7 @@ impl<'local, 'interner> Interpreter<'local, 'interner> { } // Now actually cast the lhs, bit casting and wrapping as necessary - match cast.r#type.follow_bindings() { + match typ.follow_bindings() { Type::FieldElement => { if lhs_is_negative { lhs = FieldElement::zero() - lhs; @@ -1443,8 +1448,7 @@ impl<'local, 'interner> Interpreter<'local, 'interner> { } Type::Integer(sign, bit_size) => match (sign, bit_size) { (Signedness::Unsigned, IntegerBitSize::One) => { - let location = interner.expr_location(&id); - Err(InterpreterError::TypeUnsupported { typ: cast.r#type.clone(), location }) + Err(InterpreterError::TypeUnsupported { typ: typ.clone(), location }) } (Signedness::Unsigned, IntegerBitSize::Eight) => cast_to_int!(lhs, to_u128, u8, U8), (Signedness::Unsigned, IntegerBitSize::Sixteen) => { @@ -1457,8 +1461,7 @@ impl<'local, 'interner> Interpreter<'local, 'interner> { cast_to_int!(lhs, to_u128, u64, U64) } (Signedness::Signed, IntegerBitSize::One) => { - let location = interner.expr_location(&id); - Err(InterpreterError::TypeUnsupported { typ: cast.r#type.clone(), location }) + Err(InterpreterError::TypeUnsupported { typ: typ.clone(), location }) } (Signedness::Signed, IntegerBitSize::Eight) => cast_to_int!(lhs, to_i128, i8, I8), (Signedness::Signed, IntegerBitSize::Sixteen) => { @@ -1472,10 +1475,7 @@ impl<'local, 'interner> Interpreter<'local, 'interner> { } }, Type::Bool => Ok(Value::Bool(!lhs.is_zero() || lhs_is_negative)), - typ => { - let location = interner.expr_location(&id); - Err(InterpreterError::CastToNonNumericType { typ, location }) - } + typ => Err(InterpreterError::CastToNonNumericType { typ, location }), } } diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs index 3d8ccf78926..2e672e3d0d5 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs @@ -64,6 +64,7 @@ impl<'local, 'context> Interpreter<'local, 'context> { "array_len" => array_len(interner, arguments, location), "array_refcount" => Ok(Value::U32(0)), "assert_constant" => Ok(Value::Bool(true)), + "as_field" => as_field(interner, arguments, location), "as_slice" => as_slice(interner, arguments, location), "ctstring_eq" => ctstring_eq(arguments, location), "ctstring_hash" => ctstring_hash(arguments, location), @@ -116,6 +117,7 @@ impl<'local, 'context> Interpreter<'local, 'context> { "field_less_than" => field_less_than(arguments, location), "fmtstr_as_ctstring" => fmtstr_as_ctstring(interner, arguments, location), "fmtstr_quoted_contents" => fmtstr_quoted_contents(interner, arguments, location), + "from_field" => from_field(interner, arguments, return_type, location), "fresh_type_variable" => fresh_type_variable(interner), "function_def_add_attribute" => function_def_add_attribute(self, arguments, location), "function_def_body" => function_def_body(interner, arguments, location), @@ -290,6 +292,16 @@ fn array_as_str_unchecked( Ok(Value::String(Rc::new(string))) } +// fn as_field(x: T) -> Field {} +fn as_field( + interner: &NodeInterner, + arguments: Vec<(Value, Location)>, + location: Location, +) -> IResult { + let (value, value_location) = check_one_argument(arguments, location)?; + Interpreter::evaluate_cast_one_step(&Type::FieldElement, value_location, value, interner) +} + fn as_slice( interner: &NodeInterner, arguments: Vec<(Value, Location)>, @@ -2224,6 +2236,17 @@ fn fmtstr_quoted_contents( Ok(Value::Quoted(Rc::new(tokens))) } +// fn from_field(x: Field) -> T {} +fn from_field( + interner: &NodeInterner, + arguments: Vec<(Value, Location)>, + return_type: Type, + location: Location, +) -> IResult { + let (value, value_location) = check_one_argument(arguments, location)?; + Interpreter::evaluate_cast_one_step(&return_type, value_location, value, interner) +} + // fn fresh_type_variable() -> Type fn fresh_type_variable(interner: &NodeInterner) -> IResult { Ok(Value::Type(interner.next_type_variable_with_kind(Kind::Any))) diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/value.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/value.rs index 945fb45026d..e5c55e2b0be 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/value.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/value.rs @@ -1,6 +1,6 @@ use std::{borrow::Cow, rc::Rc, vec}; -use acvm::{AcirField, FieldElement}; +use acvm::FieldElement; use im::Vector; use iter_extended::{try_vecmap, vecmap}; use noirc_errors::{Location, Span}; @@ -409,6 +409,9 @@ impl Value { Value::Pointer(element, true) => { return element.unwrap_or_clone().into_hir_expression(interner, location); } + Value::Closure(hir_lambda, _args, _typ, _opt_func_id, _module_id) => { + HirExpression::Lambda(hir_lambda) + } Value::TypedExpr(TypedExpr::StmtId(..)) | Value::Expr(..) | Value::Pointer(..) @@ -420,7 +423,6 @@ impl Value { | Value::Zeroed(_) | Value::Type(_) | Value::UnresolvedType(_) - | Value::Closure(..) | Value::ModuleDefinition(_) => { let typ = self.get_type().into_owned(); let value = self.display(interner).to_string(); @@ -502,19 +504,28 @@ impl Value { Ok(vec![token]) } - /// Converts any unsigned `Value` into a `u128`. - /// Returns `None` for negative integers. - pub(crate) fn to_u128(&self) -> Option { + /// Returns false for non-integral `Value`s. + pub(crate) fn is_integral(&self) -> bool { + use Value::*; + matches!( + self, + Field(_) | I8(_) | I16(_) | I32(_) | I64(_) | U8(_) | U16(_) | U32(_) | U64(_) + ) + } + + /// Converts any non-negative `Value` into a `FieldElement`. + /// Returns `None` for negative integers and non-integral `Value`s. + pub(crate) fn to_field_element(&self) -> Option { match self { - Self::Field(value) => Some(value.to_u128()), - Self::I8(value) => (*value >= 0).then_some(*value as u128), - Self::I16(value) => (*value >= 0).then_some(*value as u128), - Self::I32(value) => (*value >= 0).then_some(*value as u128), - Self::I64(value) => (*value >= 0).then_some(*value as u128), - Self::U8(value) => Some(*value as u128), - Self::U16(value) => Some(*value as u128), - Self::U32(value) => Some(*value as u128), - Self::U64(value) => Some(*value as u128), + Self::Field(value) => Some(*value), + Self::I8(value) => (*value >= 0).then_some((*value as u128).into()), + Self::I16(value) => (*value >= 0).then_some((*value as u128).into()), + Self::I32(value) => (*value >= 0).then_some((*value as u128).into()), + Self::I64(value) => (*value >= 0).then_some((*value as u128).into()), + Self::U8(value) => Some((*value as u128).into()), + Self::U16(value) => Some((*value as u128).into()), + Self::U32(value) => Some((*value as u128).into()), + Self::U64(value) => Some((*value as u128).into()), _ => None, } } diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/errors.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/errors.rs index 774836f8992..8817904c6f5 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/errors.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/errors.rs @@ -5,10 +5,13 @@ use thiserror::Error; use crate::{ ast::{Ident, UnsupportedNumericGenericType}, - hir::{comptime::InterpreterError, type_check::TypeCheckError}, + hir::{ + comptime::{InterpreterError, Value}, + type_check::TypeCheckError, + }, parser::ParserError, usage_tracker::UnusedItem, - Type, + Kind, Type, }; use super::import::PathResolutionError; @@ -101,6 +104,14 @@ pub enum ResolverError { MutableGlobal { span: Span }, #[error("Globals must have a specified type")] UnspecifiedGlobalType { span: Span, expected_type: Type }, + #[error("Global failed to evaluate")] + UnevaluatedGlobalType { span: Span }, + #[error("Globals used in a type position must be non-negative")] + NegativeGlobalType { span: Span, global_value: Value }, + #[error("Globals used in a type position must be integers")] + NonIntegralGlobalType { span: Span, global_value: Value }, + #[error("Global value `{global_value}` is larger than its kind's maximum value")] + GlobalLargerThanKind { span: Span, global_value: FieldElement, kind: Kind }, #[error("Self-referential structs are not supported")] SelfReferentialStruct { span: Span }, #[error("#[no_predicates] attribute is only allowed on constrained functions")] @@ -443,6 +454,34 @@ impl<'a> From<&'a ResolverError> for Diagnostic { *span, ) }, + ResolverError::UnevaluatedGlobalType { span } => { + Diagnostic::simple_error( + "Global failed to evaluate".to_string(), + String::new(), + *span, + ) + } + ResolverError::NegativeGlobalType { span, global_value } => { + Diagnostic::simple_error( + "Globals used in a type position must be non-negative".to_string(), + format!("But found value `{global_value:?}`"), + *span, + ) + } + ResolverError::NonIntegralGlobalType { span, global_value } => { + Diagnostic::simple_error( + "Globals used in a type position must be integers".to_string(), + format!("But found value `{global_value:?}`"), + *span, + ) + } + ResolverError::GlobalLargerThanKind { span, global_value, kind } => { + Diagnostic::simple_error( + format!("Global value `{global_value}` is larger than its kind's maximum value"), + format!("Global's kind inferred to be `{kind}`"), + *span, + ) + } ResolverError::SelfReferentialStruct { span } => { Diagnostic::simple_error( "Self-referential structs are not supported".into(), diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/type_check/errors.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/type_check/errors.rs index 15b8d50c78b..08864b919e3 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir/type_check/errors.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/type_check/errors.rs @@ -66,9 +66,6 @@ pub enum TypeCheckError { from_value: FieldElement, span: Span, }, - // TODO(https://github.com/noir-lang/noir/issues/6238): implement handling for larger types - #[error("Expected type {expected_kind} when evaluating globals, but found {expr_kind} (this warning may become an error in the future)")] - EvaluatedGlobalIsntU32 { expected_kind: String, expr_kind: String, expr_span: Span }, #[error("Expected {expected:?} found {found:?}")] ArityMisMatch { expected: usize, found: usize, span: Span }, #[error("Return type in a function cannot be public")] @@ -275,15 +272,6 @@ impl<'a> From<&'a TypeCheckError> for Diagnostic { *span, ) } - // TODO(https://github.com/noir-lang/noir/issues/6238): implement - // handling for larger types - TypeCheckError::EvaluatedGlobalIsntU32 { expected_kind, expr_kind, expr_span } => { - Diagnostic::simple_warning( - format!("Expected type {expected_kind} when evaluating globals, but found {expr_kind} (this warning may become an error in the future)"), - String::new(), - *expr_span, - ) - } TypeCheckError::TraitMethodParameterTypeMismatch { method_name, expected_typ, actual_typ, parameter_index, parameter_span } => { Diagnostic::simple_error( format!("Parameter #{parameter_index} of method `{method_name}` must be of type {expected_typ}, not {actual_typ}"), diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir_def/stmt.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir_def/stmt.rs index 0258cfd8ddb..c42b8230290 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir_def/stmt.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir_def/stmt.rs @@ -31,15 +31,31 @@ pub struct HirLetStatement { pub expression: ExprId, pub attributes: Vec, pub comptime: bool, + pub is_global_let: bool, } impl HirLetStatement { + pub fn new( + pattern: HirPattern, + r#type: Type, + expression: ExprId, + attributes: Vec, + comptime: bool, + is_global_let: bool, + ) -> HirLetStatement { + Self { pattern, r#type, expression, attributes, comptime, is_global_let } + } + pub fn ident(&self) -> HirIdent { match &self.pattern { HirPattern::Identifier(ident) => ident.clone(), _ => panic!("can only fetch hir ident from HirPattern::Identifier"), } } + + pub fn runs_comptime(&self) -> bool { + self.comptime || self.is_global_let + } } #[derive(Debug, Clone)] diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir_def/types.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir_def/types.rs index 2c9a44c079d..0ed6399296b 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir_def/types.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir_def/types.rs @@ -226,6 +226,10 @@ impl Kind { // Kind::Integer unifies with Kind::IntegerOrField (Kind::Integer | Kind::IntegerOrField, Kind::Integer | Kind::IntegerOrField) => true, + // Kind::IntegerOrField unifies with Kind::Numeric(_) + (Kind::IntegerOrField, Kind::Numeric(_typ)) + | (Kind::Numeric(_typ), Kind::IntegerOrField) => true, + // Kind::Numeric unifies along its Type argument (Kind::Numeric(lhs), Kind::Numeric(rhs)) => { let mut bindings = TypeBindings::new(); @@ -255,7 +259,8 @@ impl Kind { match self { Kind::IntegerOrField => Some(Type::default_int_or_field_type()), Kind::Integer => Some(Type::default_int_type()), - Kind::Any | Kind::Normal | Kind::Numeric(..) => None, + Kind::Numeric(typ) => Some(*typ.clone()), + Kind::Any | Kind::Normal => None, } } @@ -267,7 +272,7 @@ impl Kind { } /// Ensure the given value fits in self.integral_maximum_size() - fn ensure_value_fits( + pub(crate) fn ensure_value_fits( &self, value: FieldElement, span: Span, @@ -2210,6 +2215,7 @@ impl Type { Type::NamedGeneric(binding, _) | Type::TypeVariable(binding) => { substitute_binding(binding) } + // Do not substitute_helper fields, it can lead to infinite recursion // and we should not match fields when type checking anyway. Type::Struct(fields, args) => { diff --git a/noir/noir-repo/compiler/noirc_frontend/src/monomorphization/mod.rs b/noir/noir-repo/compiler/noirc_frontend/src/monomorphization/mod.rs index b31a5744d09..5297a89cc95 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/monomorphization/mod.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/monomorphization/mod.rs @@ -1133,7 +1133,7 @@ impl<'interner> Monomorphizer<'interner> { | HirType::Error | HirType::Quoted(_) => Ok(()), HirType::Constant(_value, kind) => { - if kind.is_error() { + if kind.is_error() || kind.default_type().is_none() { Err(MonomorphizationError::UnknownConstant { location }) } else { Ok(()) @@ -1154,7 +1154,6 @@ impl<'interner> Monomorphizer<'interner> { Ok(()) } - HirType::TypeVariable(ref binding) => { let type_var_kind = match &*binding.borrow() { TypeBinding::Bound(binding) => { diff --git a/noir/noir-repo/compiler/noirc_frontend/src/node_interner.rs b/noir/noir-repo/compiler/noirc_frontend/src/node_interner.rs index 6d70ea2fd6d..ae30b68c095 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/node_interner.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/node_interner.rs @@ -849,6 +849,7 @@ impl NodeInterner { let id = GlobalId(self.globals.len()); let location = Location::new(ident.span(), file); let name = ident.to_string(); + let definition_id = self.push_definition(name, mutable, comptime, DefinitionKind::Global(id), location); @@ -884,6 +885,7 @@ impl NodeInterner { ) -> GlobalId { let statement = self.push_stmt(HirStatement::Error); let span = name.span(); + let id = self .push_global(name, local_id, crate_id, statement, file, attributes, mutable, comptime); self.push_stmt_location(statement, span, file); diff --git a/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/global.rs b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/global.rs index 5ece510022a..3a4f6d922a4 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/global.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/global.rs @@ -23,6 +23,7 @@ impl<'a> Parser<'a> { // and throw the error in name resolution. let attributes = self.validate_secondary_attributes(attributes); + let is_global_let = true; let Some(ident) = self.eat_ident() else { self.eat_semicolons(); @@ -35,6 +36,7 @@ impl<'a> Parser<'a> { expression: Expression { kind: ExpressionKind::Error, span: Span::default() }, attributes, comptime, + is_global_let, }; }; @@ -53,7 +55,7 @@ impl<'a> Parser<'a> { self.expected_token(Token::Semicolon); } - LetStatement { pattern, r#type: typ, expression, attributes, comptime } + LetStatement { pattern, r#type: typ, expression, attributes, comptime, is_global_let } } } @@ -105,6 +107,7 @@ mod tests { assert_eq!("foo", name.to_string()); assert!(matches!(let_statement.r#type.typ, UnresolvedTypeData::Unspecified)); assert!(!let_statement.comptime); + assert!(let_statement.is_global_let); assert_eq!(visibility, ItemVisibility::Private); } diff --git a/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/statement.rs b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/statement.rs index ff6117c9348..ab86f7d6649 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/statement.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/statement.rs @@ -364,7 +364,14 @@ impl<'a> Parser<'a> { Expression { kind: ExpressionKind::Error, span: self.current_token_span } }; - Some(LetStatement { pattern, r#type, expression, attributes, comptime: false }) + Some(LetStatement { + pattern, + r#type, + expression, + attributes, + comptime: false, + is_global_let: false, + }) } /// ConstrainStatement diff --git a/noir/noir-repo/compiler/noirc_frontend/src/tests.rs b/noir/noir-repo/compiler/noirc_frontend/src/tests.rs index 8ddf1b571e6..1aed3d62d30 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/tests.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/tests.rs @@ -1287,11 +1287,15 @@ fn lambda$f1(mut env$l1: (Field)) -> Field { check_rewrite(src, expected_rewrite); } +// TODO(https://github.com/noir-lang/noir/issues/6780): currently failing +// with a stack overflow #[test] +#[ignore] fn deny_cyclic_globals() { let src = r#" global A: u32 = B; global B: u32 = A; + fn main() {} "#; @@ -1991,9 +1995,6 @@ fn numeric_generic_u16_array_size() { )); } -// TODO(https://github.com/noir-lang/noir/issues/6238): -// The EvaluatedGlobalIsntU32 warning is a stopgap -// (originally from https://github.com/noir-lang/noir/issues/6125) #[test] fn numeric_generic_field_larger_than_u32() { let src = r#" @@ -2006,29 +2007,16 @@ fn numeric_generic_field_larger_than_u32() { } "#; let errors = get_program_errors(src); - assert_eq!(errors.len(), 2); - assert!(matches!( - errors[0].0, - CompilationError::TypeError(TypeCheckError::EvaluatedGlobalIsntU32 { .. }), - )); - assert!(matches!( - errors[1].0, - CompilationError::ResolverError(ResolverError::IntegerTooLarge { .. }) - )); + assert_eq!(errors.len(), 0); } -// TODO(https://github.com/noir-lang/noir/issues/6238): -// The EvaluatedGlobalIsntU32 warning is a stopgap -// (originally from https://github.com/noir-lang/noir/issues/6126) #[test] fn numeric_generic_field_arithmetic_larger_than_u32() { let src = r#" struct Foo {} - impl Foo { - fn size(self) -> Field { - F - } + fn size(_x: Foo) -> Field { + F } // 2^32 - 1 @@ -2039,21 +2027,11 @@ fn numeric_generic_field_arithmetic_larger_than_u32() { } fn main() { - let _ = foo::().size(); + let _ = size(foo::()); } "#; let errors = get_program_errors(src); - assert_eq!(errors.len(), 2); - - assert!(matches!( - errors[0].0, - CompilationError::TypeError(TypeCheckError::EvaluatedGlobalIsntU32 { .. }), - )); - - assert!(matches!( - errors[1].0, - CompilationError::ResolverError(ResolverError::UnusedVariable { .. }) - )); + assert_eq!(errors.len(), 0); } #[test] @@ -2180,25 +2158,11 @@ fn numeric_generics_type_kind_mismatch() { } "#; let errors = get_program_errors(src); - assert_eq!(errors.len(), 3); - - // TODO(https://github.com/noir-lang/noir/issues/6238): - // The EvaluatedGlobalIsntU32 warning is a stopgap + assert_eq!(errors.len(), 1); assert!(matches!( errors[0].0, - CompilationError::TypeError(TypeCheckError::EvaluatedGlobalIsntU32 { .. }), - )); - - assert!(matches!( - errors[1].0, CompilationError::TypeError(TypeCheckError::TypeKindMismatch { .. }), )); - - // TODO(https://github.com/noir-lang/noir/issues/6238): see above - assert!(matches!( - errors[2].0, - CompilationError::TypeError(TypeCheckError::EvaluatedGlobalIsntU32 { .. }), - )); } #[test] @@ -3219,20 +3183,20 @@ fn dont_infer_globals_to_u32_from_type_use() { } "#; - let errors = get_program_errors(src); - assert_eq!(errors.len(), 3); - assert!(matches!( - errors[0].0, - CompilationError::ResolverError(ResolverError::UnspecifiedGlobalType { .. }) - )); - assert!(matches!( - errors[1].0, - CompilationError::ResolverError(ResolverError::UnspecifiedGlobalType { .. }) - )); - assert!(matches!( - errors[2].0, - CompilationError::ResolverError(ResolverError::UnspecifiedGlobalType { .. }) - )); + let mut errors = get_program_errors(src); + assert_eq!(errors.len(), 6); + for (error, _file_id) in errors.drain(0..3) { + assert!(matches!( + error, + CompilationError::ResolverError(ResolverError::UnspecifiedGlobalType { .. }) + )); + } + for (error, _file_id) in errors { + assert!(matches!( + error, + CompilationError::TypeError(TypeCheckError::TypeKindMismatch { .. }) + )); + } } #[test] @@ -3242,7 +3206,8 @@ fn dont_infer_partial_global_types() { pub global NESTED_ARRAY: [[Field; _]; 3] = [[]; 3]; pub global STR: str<_> = "hi"; pub global NESTED_STR: [str<_>] = &["hi"]; - pub global FMT_STR: fmtstr<_, _> = f"hi {ARRAY}"; + pub global FORMATTED_VALUE: str<5> = "there"; + pub global FMT_STR: fmtstr<_, _> = f"hi {FORMATTED_VALUE}"; pub global TUPLE_WITH_MULTIPLE: ([str<_>], [[Field; _]; 3]) = (&["hi"], [[]; 3]); fn main() { } @@ -3318,13 +3283,9 @@ fn non_u32_as_array_length() { "#; let errors = get_program_errors(src); - assert_eq!(errors.len(), 2); + assert_eq!(errors.len(), 1); assert!(matches!( errors[0].0, - CompilationError::TypeError(TypeCheckError::EvaluatedGlobalIsntU32 { .. }) - )); - assert!(matches!( - errors[1].0, CompilationError::TypeError(TypeCheckError::TypeKindMismatch { .. }) )); } diff --git a/noir/noir-repo/compiler/noirc_frontend/src/tests/arithmetic_generics.rs b/noir/noir-repo/compiler/noirc_frontend/src/tests/arithmetic_generics.rs index 3328fe439ae..83de9c077ab 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/tests/arithmetic_generics.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/tests/arithmetic_generics.rs @@ -153,3 +153,49 @@ fn arithmetic_generics_checked_cast_indirect_zeros() { panic!("unexpected error: {:?}", monomorphization_error); } } + +#[test] +fn global_numeric_generic_larger_than_u32() { + // Regression test for https://github.com/noir-lang/noir/issues/6125 + let source = r#" + global A: Field = 4294967297; + + fn foo() { } + + fn main() { + let _ = foo::(); + } + "#; + let errors = get_program_errors(source); + assert_eq!(errors.len(), 0); +} + +#[test] +fn global_arithmetic_generic_larger_than_u32() { + // Regression test for https://github.com/noir-lang/noir/issues/6126 + let source = r#" + struct Foo {} + + impl Foo { + fn size(self) -> Field { + let _ = self; + F + } + } + + // 2^32 - 1 + global A: Field = 4294967295; + + // Avoiding overflow succeeds: + // fn foo() -> Foo { + fn foo() -> Foo { + Foo {} + } + + fn main() { + let _ = foo::().size(); + } + "#; + let errors = get_program_errors(source); + assert_eq!(errors.len(), 0); +} diff --git a/noir/noir-repo/cspell.json b/noir/noir-repo/cspell.json index 5c707e92e21..9a4bca1e339 100644 --- a/noir/noir-repo/cspell.json +++ b/noir/noir-repo/cspell.json @@ -32,6 +32,7 @@ "boilerplates", "bridgekeeper", "brillig", + "bunx", "bytecount", "cachix", "callsite", @@ -242,9 +243,11 @@ "walkdir", "wasi", "wasmer", + "webapps", "Weierstraß", "whitespace", "whitespaces", + "YOLO", "zkhash", "zshell" ], diff --git a/noir/noir-repo/docs/docs/tutorials/noirjs_app.md b/noir/noir-repo/docs/docs/tutorials/noirjs_app.md index 6e69ea0bbed..8967ee005ce 100644 --- a/noir/noir-repo/docs/docs/tutorials/noirjs_app.md +++ b/noir/noir-repo/docs/docs/tutorials/noirjs_app.md @@ -1,186 +1,91 @@ --- -title: Building a web app with NoirJS +title: Building a web app with Noir and Barretenberg description: Learn how to setup a new app that uses Noir to generate and verify zero-knowledge SNARK proofs in a typescript or javascript environment. keywords: [how to, guide, javascript, typescript, noir, barretenberg, zero-knowledge, proofs, app] sidebar_position: 0 pagination_next: noir/concepts/data_types/index --- -NoirJS is a set of packages meant to work both in a browser and a server environment. In this tutorial, we will build a simple web app using them. From here, you should get an idea on how to proceed with your own Noir projects! +NoirJS is a Typescript package meant to work both in a browser and a server environment. -You can find the complete app code for this guide [here](https://github.com/noir-lang/tiny-noirjs-app). - -## Setup - -:::note - -Feel free to use whatever versions, just keep in mind that Nargo and the NoirJS packages are meant to be in sync. For example, Nargo 0.31.x matches `noir_js@0.31.x`, etc. - -In this guide, we will be pinned to 0.31.0. - -::: - -Before we start, we want to make sure we have Node, Nargo and the Barretenberg proving system (`bb`) installed. - -We start by opening a terminal and executing `node --version`. If we don't get an output like `v20.10.0`, that means node is not installed. Let's do that by following the handy [nvm guide](https://github.com/nvm-sh/nvm?tab=readme-ov-file#install--update-script). - -As for `Nargo`, we can follow the [Nargo guide](../getting_started/quick_start.md) to install it. If you're lazy, just paste this on a terminal and run `noirup`: - -```sh -curl -L https://raw.githubusercontent.com/noir-lang/noirup/main/install | bash -``` +In this tutorial, we will combine NoirJS with Aztec's Barretenberg backend to build a simple web app. From here, you should get an idea on how to proceed with your own Noir projects! -Follow the instructions on [this page](https://github.com/AztecProtocol/aztec-packages/tree/master/barretenberg/cpp/src/barretenberg/bb#installation) to install `bb`. -Version 0.41.0 is compatible with `nargo` version 0.31.0, which you can install with `bbup -v 0.41.0` once `bbup` is installed. - -Easy enough. Onwards! - -## Our project - -ZK is a powerful technology. An app that doesn't reveal one of the inputs to _anyone_ is almost unbelievable, yet Noir makes it as easy as a single line of code. - -In fact, it's so simple that it comes nicely packaged in `nargo`. Let's do that! +You can find the complete app code for this guide [here](https://github.com/noir-lang/tiny-noirjs-app). -### Nargo +## Dependencies -Run: +Before we start, we want to make sure we have Node installed. For convenience (and speed), we can just install [Bun](https://bun.sh) as our package manager, and Node will work out-of-the-box: ```bash -nargo new circuit +curl -fsSL https://bun.sh/install | bash ``` -And... That's about it. Your program is ready to be compiled and run. +Let's go barebones. Doing the bare minimum is not only simple, but also allows you to easily adapt it to almost any frontend framework. -To compile, let's `cd` into the `circuit` folder to enter our project, and call: +Barebones means we can immediately start with the dependencies even on an empty folder 😈: ```bash -nargo compile +bun i @noir-lang/noir_wasm@1.0.0-beta.0 @noir-lang/noir_js@1.0.0-beta.0 @aztec/bb.js@0.63.1 ``` -This compiles our circuit into `json` format and add it to a new `target` folder. +Wait, what are these dependencies? -:::info +- `noir_wasm` is the `wasm` version of the Noir compiler. Although most developers prefer to use `nargo` for compiling, there's nothing wrong with `noir_wasm`. We like `noir_wasm`. +- `noir_js` is the main Noir package. It will execute our program, and generate the witness that will be sent to the backend. +- `bb.js` is the Typescript interface for Aztec's Barretenberg proving backend. It also uses the `wasm` version in order to run on the browser. -At this point in the tutorial, your folder structure should look like this: +:::info -```tree -. -└── circuit <---- our working directory - β”œβ”€β”€ Nargo.toml - β”œβ”€β”€ src - β”‚ └── main.nr - └── target - └── circuit.json -``` +In this guide, we will install versions pinned to 1.0.0-beta.0. These work with Barretenberg version 0.63.1, so we are using that one version too. Feel free to try with older or later versions, though! ::: -### Node and Vite - -If you want to explore Nargo, feel free to go on a side-quest now and follow the steps in the -[getting started](../getting_started/quick_start.md) guide. However, we want our app to run on the browser, so we need Vite. +## Setting up our Noir program -Vite is a powerful tool to generate static websites. While it provides all kinds of features, let's just go barebones with some good old vanilla JS. +ZK is a powerful technology. An app that reveals computational correctness but doesn't reveal some of its inputs is almost unbelievable, yet Noir makes it as easy as a single line of code. -To do this this, go back to the previous folder (`cd ..`) and create a new vite project by running `npm create vite` and choosing "Vanilla" and "Javascript". +:::tip -A wild `vite-project` directory should now appear in your root folder! Let's not waste any time and dive right in: +It's not just you. We also enjoy syntax highlighting. [Check out the Language Server](../tooling/language_server.md) -```bash -cd vite-project -``` +::: -### Setting Up Vite and Configuring the Project - -Before we proceed with any coding, let's get our environment tailored for Noir. We'll start by laying down the foundations with a `vite.config.js` file. This little piece of configuration is our secret sauce for making sure everything meshes well with the NoirJS libraries and other special setups we might need, like handling WebAssembly modules. Here’s how you get that going: - -#### Creating the vite.config.js - -In your freshly minted `vite-project` folder, create a new file named `vite.config.js` and open it in your code editor. Paste the following to set the stage: - -```javascript -import { defineConfig } from 'vite'; -import copy from 'rollup-plugin-copy'; -import fs from 'fs'; -import path from 'path'; - -const wasmContentTypePlugin = { - name: 'wasm-content-type-plugin', - configureServer(server) { - server.middlewares.use(async (req, res, next) => { - if (req.url.endsWith('.wasm')) { - res.setHeader('Content-Type', 'application/wasm'); - const newPath = req.url.replace('deps', 'dist'); - const targetPath = path.join(__dirname, newPath); - const wasmContent = fs.readFileSync(targetPath); - return res.end(wasmContent); - } - next(); - }); - }, -}; +All you need is a `main.nr` and a `Nargo.toml` file. You can follow the [noirup](../getting_started/noir_installation.md) installation and just run `noirup -v 1.0.0-beta.0`, or just create them by hand: -export default defineConfig(({ command }) => { - if (command === 'serve') { - return { - build: { - target: 'esnext', - rollupOptions: { - external: ['@aztec/bb.js'] - } - }, - optimizeDeps: { - esbuildOptions: { - target: 'esnext' - } - }, - plugins: [ - copy({ - targets: [{ src: 'node_modules/**/*.wasm', dest: 'node_modules/.vite/dist' }], - copySync: true, - hook: 'buildStart', - }), - command === 'serve' ? wasmContentTypePlugin : [], - ], - }; - } - - return {}; -}); +```bash +mkdir -p circuit/src +touch circuit/src/main.nr circuit/Nargo.toml ``` -#### Install Dependencies - -Now that our stage is set, install the necessary NoirJS packages along with our other dependencies: +To make our program interesting, let's give it a real use-case scenario: Bob wants to prove he is older than 18, without disclosing his age. Open `main.nr` and write: -```bash -npm install && npm install @noir-lang/backend_barretenberg@0.31.0 @noir-lang/noir_js@0.31.0 -npm install rollup-plugin-copy --save-dev +```rust +fn main(age: u8) { + assert(age >= 18); +} ``` -:::info - -At this point in the tutorial, your folder structure should look like this: +This program accepts a private input called age, and simply proves this number is higher than 18. But to run this code, we need to give the compiler a `Nargo.toml` with at least a name and a type: -```tree -. -└── circuit - └── ...etc... -└── vite-project <---- our working directory - └── ...etc... +```toml +[package] +name = "circuit" +type = "bin" ``` -::: +This is all that we need to get started with Noir. -#### Some cleanup +![my heart is ready for you, noir.js](@site/static/img/memes/titanic.jpeg) -`npx create vite` is amazing but it creates a bunch of files we don't really need for our simple example. Actually, let's just delete everything except for `vite.config.js`, `index.html`, `main.js` and `package.json`. I feel lighter already. +## Setting up our app -![my heart is ready for you, noir.js](@site/static/img/memes/titanic.jpeg) +Remember when apps only had one `html` and one `js` file? Well, that's enough for Noir webapps. Let's create them: -## HTML +```bash +touch index.html index.js +``` -Our app won't run like this, of course. We need some working HTML, at least. Let's open our broken-hearted `index.html` and replace everything with this code snippet: +And add something useful to our HTML file: ```html @@ -200,11 +105,11 @@ Our app won't run like this, of course. We need some working HTML, at least. Let - +

Noir app

- - + +

Logs

@@ -214,32 +119,26 @@ Our app won't run like this, of course. We need some working HTML, at least. Let ``` -It _could_ be a beautiful UI... Depending on which universe you live in. - -## Some good old vanilla Javascript - -Our love for Noir needs undivided attention, so let's just open `main.js` and delete everything (this is where the romantic scenery becomes a bit creepy). +It _could_ be a beautiful UI... Depending on which universe you live in. In any case, we're using some scary CSS to make two boxes that will show cool things on the screen. -Start by pasting in this boilerplate code: +As for the JS, real madmen could just `console.log` everything, but let's say we want to see things happening (the true initial purpose of JS... right?). Here's some boilerplate for that. Just paste it in `index.js`: ```js -function display(container, msg) { - const c = document.getElementById(container); - const p = document.createElement('p'); - p.textContent = msg; - c.appendChild(p); -} +const show = (id, content) => { + const container = document.getElementById(id); + container.appendChild(document.createTextNode(content)); + container.appendChild(document.createElement("br")); +}; -document.getElementById('submitGuess').addEventListener('click', async () => { - try { - // here's where love happens - } catch (err) { - display('logs', 'Oh πŸ’” Wrong guess'); - } +document.getElementById("submit").addEventListener("click", async () => { + try { + // noir goes here + } catch { + show("logs", "Oh πŸ’”"); + } }); -``` -The display function doesn't do much. We're simply manipulating our website to see stuff happening. For example, if the proof fails, it will simply log a broken heart 😒 +``` :::info @@ -248,30 +147,56 @@ At this point in the tutorial, your folder structure should look like this: ```tree . └── circuit - └── ...same as above -└── vite-project - β”œβ”€β”€ vite.config.js - β”œβ”€β”€ main.js - β”œβ”€β”€ package.json - └── index.html + └── src + └── main.nr + Nargo.toml + index.js + package.json + index.html + ...etc ``` -You'll see other files and folders showing up (like `package-lock.json`, `node_modules`) but you shouldn't have to care about those. - ::: -## Some NoirJS +## Compile compile compile -We're starting with the good stuff now. If you've compiled the circuit as described above, you should have a `json` file we want to import at the very top of our `main.js` file: +Finally we're up for something cool. But before we can execute a Noir program, we need to compile it into ACIR: an abstract representation. Here's where `noir_wasm` comes in. -```ts -import circuit from '../circuit/target/circuit.json'; +`noir_wasm` expects a filesystem so it can resolve dependencies. While we could use the `public` folder, let's just import those using the nice `?url` syntax provided by vite. At the top of the file: + +```js +import { compile, createFileManager } from "@noir-lang/noir_wasm" + +import main from "./circuit/src/main.nr?url"; +import nargoToml from "./circuit/Nargo.toml?url"; ``` -[Noir is backend-agnostic](../index.mdx#whats-new-about-noir). We write Noir, but we also need a proving backend. That's why we need to import and instantiate the two dependencies we installed above: `BarretenbergBackend` and `Noir`. Let's import them right below: +Compiling on the browser is common enough that `createFileManager` already gives us a nice in-memory filesystem we can use. So all we need to compile is fetching these files, writing them to our filesystem, and compile. Add this function: ```js -import { BarretenbergBackend, BarretenbergVerifier as Verifier } from '@noir-lang/backend_barretenberg'; +export async function getCircuit() { + const fm = createFileManager("/"); + const { body } = await fetch(main); + const { body: nargoTomlBody } = await fetch(nargoToml); + + fm.writeFile("./src/main.nr", body); + fm.writeFile("./Nargo.toml", nargoTomlBody); + return await compile(fm); +} +``` + +:::tip + +As you can imagine, with `node` it's all conveniently easier since you get native access to `fs`... + +::: + +## Some more JS + +We're starting with the good stuff now. We want to execute our circuit to get the witness, and then feed that witness to Barretenberg. Luckily, both packages are quite easy to work with. Let's import them at the top of the file: + +```js +import { UltraHonkBackend } from '@aztec/bb.js'; import { Noir } from '@noir-lang/noir_js'; ``` @@ -279,88 +204,103 @@ And instantiate them inside our try-catch block: ```ts // try { -const backend = new BarretenbergBackend(circuit); -const noir = new Noir(circuit); +const { program } = await getCircuit(); +const noir = new Noir(program); +const backend = new UltraHonkBackend(program.bytecode); // } ``` -:::note +:::warning -For the remainder of the tutorial, everything will be happening inside the `try` block +WASMs are not always easy to work with. In our case, `vite` likes serving them with the wrong MIME type. There are different fixes but we found the easiest one is just YOLO instantiating the WASMs manually. Paste this at the top of the file, just below the other imports, and it will work just fine: + +```js +import initNoirC from "@noir-lang/noirc_abi"; +import initACVM from "@noir-lang/acvm_js"; +import acvm from "@noir-lang/acvm_js/web/acvm_js_bg.wasm?url"; +import noirc from "@noir-lang/noirc_abi/web/noirc_abi_wasm_bg.wasm?url"; +await Promise.all([initACVM(fetch(acvm)), initNoirC(fetch(noirc))]); +``` ::: -## Our app +## Executing and proving -Now for the app itself. We're capturing whatever is in the input when people press the submit button. Just add this: +Now for the app itself. We're capturing whatever is in the input when people press the submit button. Inside our `try` block, let's just grab that input and get its value. Noir will gladly execute it, and give us a witness: ```js -const x = parseInt(document.getElementById('guessInput').value); -const input = { x, y: 2 }; +const age = document.getElementById("age").value; +show("logs", "Generating witness... ⏳"); +const { witness } = await noir.execute({ age }); +show("logs", "Generated witness... βœ…"); + ``` +:::note + +For the remainder of the tutorial, everything will be happening inside the `try` block + +::: + Now we're ready to prove stuff! Let's feed some inputs to our circuit and calculate the proof: ```js -await setup(); // let's squeeze our wasm inits here - -display('logs', 'Generating proof... βŒ›'); -const { witness } = await noir.execute(input); +show("logs", "Generating proof... ⏳"); const proof = await backend.generateProof(witness); -display('logs', 'Generating proof... βœ…'); -display('results', proof.proof); +show("logs", "Generated proof... βœ…"); +show("results", proof.proof); ``` -You're probably eager to see stuff happening, so go and run your app now! +Our program is technically **done** . You're probably eager to see stuff happening! To serve this in a convenient way, we can use a bundler like `vite` by creating a `vite.config.js` file: + +```bash +touch vite.config.js +``` -From your terminal, run `npm run dev`. If it doesn't open a browser for you, just visit `localhost:5173`. You should now see the worst UI ever, with an ugly input. +`vite` helps us with a little catch: `bb.js` in particular uses top-level awaits which aren't supported everywhere. So we can add this to the `vite.config.js` to make the bundler optimize them: -![Getting Started 0](@site/static/img/noir_getting_started_1.png) +```js +export default { optimizeDeps: { esbuildOptions: { target: "esnext" } } }; +``` + +This should be enough for vite. We don't even need to install it, just run: + +```bash +bunx vite +``` -Now, our circuit says `fn main(x: Field, y: pub Field)`. This means only the `y` value is public, and it's hardcoded above: `input = { x, y: 2 }`. In other words, you won't need to send your secret`x` to the verifier! +If it doesn't open a browser for you, just visit `localhost:5173`. You should now see the worst UI ever, with an ugly input. -By inputting any number other than 2 in the input box and clicking "submit", you should get a valid proof. Otherwise the proof won't even generate correctly. By the way, if you're human, you shouldn't be able to understand anything on the "proof" box. That's OK. We like you, human ❀️. +![Noir Webapp UI](@site/static/img/tutorials/noirjs_webapp/webapp1.png) + +Now, our circuit requires a private input `fn main(age: u8)`, and fails if it is less than 18. Let's see if it works. Submit any number above 18 (as long as it fits in 8 bits) and you should get a valid proof. Otherwise the proof won't even generate correctly. + +By the way, if you're human, you shouldn't be able to understand anything on the "proof" box. That's OK. We like you, human ❀️. ## Verifying Time to celebrate, yes! But we shouldn't trust machines so blindly. Let's add these lines to see our proof being verified: ```js -display('logs', 'Verifying proof... βŒ›'); +show('logs', 'Verifying proof... βŒ›'); const isValid = await backend.verifyProof(proof); - -// or to cache and use the verification key: -// const verificationKey = await backend.getVerificationKey(); -// const verifier = new Verifier(); -// const isValid = await verifier.verifyProof(proof, verificationKey); - -if (isValid) display('logs', 'Verifying proof... βœ…'); +show("logs", `Proof is ${isValid ? "valid" : "invalid"}... βœ…`); ``` You have successfully generated a client-side Noir web app! ![coded app without math knowledge](@site/static/img/memes/flextape.jpeg) -## Further Reading - -You can see how noirjs is used in a full stack Next.js hardhat application in the [noir-starter repo here](https://github.com/noir-lang/noir-starter/tree/main/vite-hardhat). The example shows how to calculate a proof in the browser and verify it with a deployed Solidity verifier contract from noirjs. - -You should also check out the more advanced examples in the [noir-examples repo](https://github.com/noir-lang/noir-examples), where you'll find reference usage for some cool apps. +## Next steps -## UltraHonk Backend +At this point, you have a working ZK app that works on the browser. Actually, it works on a mobile phone too! -Barretenberg has recently exposed a new UltraHonk backend. We can use UltraHonk in NoirJS after version 0.33.0. Everything will be the same as the tutorial above, except that the class we need to import will change: +If you want to continue learning by doing, here are some challenges for you: -```js -import { UltraHonkBackend, UltraHonkVerifier as Verifier } from '@noir-lang/backend_barretenberg'; -``` - -The backend will then be instantiated as such: - -```js -const backend = new UltraHonkBackend(circuit); -``` +- Install [nargo](https://noir-lang.org/docs/getting_started/noir_installation) and write [Noir tests](../tooling/testing) +- Change the circuit to accept a [public input](../noir/concepts/data_types/#private--public-types) as the cutoff age. It could be different depending on the purpose, for example! +- Enjoy Noir's Rust-like syntax and write a struct `Country` that implements a trait `MinAge` with a method `get_min_age`. Then, make a struct `Person` have an `u8` as its age and a country of type `Country`. You can pass a `person` in JS just like a JSON object `person: { age, country: { min_age: 18 }}` -Then all the commands to prove and verify your circuit will be same. +The world is your stage, just have fun with ZK! You can see how noirjs is used in a full stack Next.js hardhat application in the [noir-starter repo here](https://github.com/noir-lang/noir-starter/tree/main/vite-hardhat). The example shows how to calculate a proof in the browser and verify it with a deployed Solidity verifier contract from noirjs. -The only feature currently unsupported with UltraHonk are [recursive proofs](../explainers/explainer-recursion.md). +Check out other starters, tools, or just cool projects in the [awesome noir repository](https://github.com/noir-lang/awesome-noir). diff --git a/noir/noir-repo/docs/static/img/tutorials/noirjs_webapp/webapp1.png b/noir/noir-repo/docs/static/img/tutorials/noirjs_webapp/webapp1.png new file mode 100644 index 0000000000000000000000000000000000000000..7591cd827e3ef91b0dde36e492f7636fb3744640 GIT binary patch literal 15009 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 String { string.push('\n'); } + let mut print_comptime = definition.comptime; + let mut opt_value = None; + + // See if we can figure out what's the global's value + if let Some(stmt) = args.interner.get_global_let_statement(id) { + print_comptime = stmt.comptime; + opt_value = get_global_value(args.interner, stmt.expression); + } + string.push_str(" "); - if definition.comptime { + if print_comptime { string.push_str("comptime "); } if definition.mutable { @@ -217,12 +225,9 @@ fn format_global(id: GlobalId, args: &ProcessRequestCallbackArgs) -> String { string.push_str(": "); string.push_str(&format!("{}", typ)); - // See if we can figure out what's the global's value - if let Some(stmt) = args.interner.get_global_let_statement(id) { - if let Some(value) = get_global_value(args.interner, stmt.expression) { - string.push_str(" = "); - string.push_str(&value); - } + if let Some(value) = opt_value { + string.push_str(" = "); + string.push_str(&value); } string.push_str(&go_to_type_links(&typ, args.interner, args.files)); @@ -233,13 +238,6 @@ fn format_global(id: GlobalId, args: &ProcessRequestCallbackArgs) -> String { } fn get_global_value(interner: &NodeInterner, expr: ExprId) -> Option { - let span = interner.expr_span(&expr); - - // Globals as array lengths are extremely common, so we try that first. - if let Ok(result) = try_eval_array_length_id(interner, expr, span) { - return Some(result.to_string()); - } - match interner.expression(&expr) { HirExpression::Literal(literal) => match literal { HirLiteral::Array(hir_array_literal) => { diff --git a/noir/noir-repo/tooling/nargo_cli/src/cli/test_cmd/formatters.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/test_cmd/formatters.rs index 1b9b2d50378..75cf14ba120 100644 --- a/noir/noir-repo/tooling/nargo_cli/src/cli/test_cmd/formatters.rs +++ b/noir/noir-repo/tooling/nargo_cli/src/cli/test_cmd/formatters.rs @@ -417,6 +417,7 @@ impl Formatter for JsonFormatter { let mut json = Map::new(); json.insert("type".to_string(), json!("test")); json.insert("name".to_string(), json!(&test_result.name)); + json.insert("suite".to_string(), json!(&test_result.package_name)); json.insert("exec_time".to_string(), json!(test_result.time_to_run.as_secs_f64())); let mut stdout = String::new(); diff --git a/noir/noir-repo/tooling/noirc_abi_wasm/build.sh b/noir/noir-repo/tooling/noirc_abi_wasm/build.sh index c07d2d8a4c1..16fb26e55db 100755 --- a/noir/noir-repo/tooling/noirc_abi_wasm/build.sh +++ b/noir/noir-repo/tooling/noirc_abi_wasm/build.sh @@ -25,7 +25,7 @@ function run_if_available { require_command jq require_command cargo require_command wasm-bindgen -#require_command wasm-opt +require_command wasm-opt self_path=$(dirname "$(readlink -f "$0")") pname=$(cargo read-manifest | jq -r '.name') diff --git a/noir/noir-repo/yarn.lock b/noir/noir-repo/yarn.lock index 3c8df2b1772..77962512b08 100644 --- a/noir/noir-repo/yarn.lock +++ b/noir/noir-repo/yarn.lock @@ -221,9 +221,9 @@ __metadata: languageName: node linkType: hard -"@aztec/bb.js@portal:../../../../barretenberg/ts::locator=integration-tests%40workspace%3Acompiler%2Fintegration-tests": - version: 0.0.0-use.local - resolution: "@aztec/bb.js@portal:../../../../barretenberg/ts::locator=integration-tests%40workspace%3Acompiler%2Fintegration-tests" +"@aztec/bb.js@npm:0.66.0": + version: 0.66.0 + resolution: "@aztec/bb.js@npm:0.66.0" dependencies: comlink: ^4.4.1 commander: ^10.0.1 @@ -232,9 +232,10 @@ __metadata: pako: ^2.1.0 tslib: ^2.4.0 bin: - bb.js: ./dest/node/main.js + bb.js: dest/node/main.js + checksum: 7295bf6543afe1c2db795a95c7ed40806de63c77e44bb4dacb2ec6a9171d1d34749150844ab47bc2499d06676e623acb408857b6aa9da702d3c576efadb8c906 languageName: node - linkType: soft + linkType: hard "@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.10.4, @babel/code-frame@npm:^7.12.11, @babel/code-frame@npm:^7.16.0, @babel/code-frame@npm:^7.22.13, @babel/code-frame@npm:^7.23.5, @babel/code-frame@npm:^7.8.3": version: 7.23.5 @@ -14123,7 +14124,7 @@ __metadata: version: 0.0.0-use.local resolution: "integration-tests@workspace:compiler/integration-tests" dependencies: - "@aztec/bb.js": "portal:../../../../barretenberg/ts" + "@aztec/bb.js": 0.66.0 "@noir-lang/noir_js": "workspace:*" "@noir-lang/noir_wasm": "workspace:*" "@nomicfoundation/hardhat-chai-matchers": ^2.0.0 From 769aa206163b794309720ada2cf46ef3afa9160c Mon Sep 17 00:00:00 2001 From: AztecBot Date: Wed, 18 Dec 2024 08:10:00 +0000 Subject: [PATCH 2/2] chore: apply sync fixes --- noir/noir-repo/acvm-repo/acvm_js/build.sh | 2 +- .../compiler/integration-tests/package.json | 2 +- noir/noir-repo/tooling/noirc_abi_wasm/build.sh | 2 +- noir/noir-repo/yarn.lock | 13 ++++++------- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/noir/noir-repo/acvm-repo/acvm_js/build.sh b/noir/noir-repo/acvm-repo/acvm_js/build.sh index 16fb26e55db..c07d2d8a4c1 100755 --- a/noir/noir-repo/acvm-repo/acvm_js/build.sh +++ b/noir/noir-repo/acvm-repo/acvm_js/build.sh @@ -25,7 +25,7 @@ function run_if_available { require_command jq require_command cargo require_command wasm-bindgen -require_command wasm-opt +#require_command wasm-opt self_path=$(dirname "$(readlink -f "$0")") pname=$(cargo read-manifest | jq -r '.name') diff --git a/noir/noir-repo/compiler/integration-tests/package.json b/noir/noir-repo/compiler/integration-tests/package.json index bfaa1cabd16..e33179f31e7 100644 --- a/noir/noir-repo/compiler/integration-tests/package.json +++ b/noir/noir-repo/compiler/integration-tests/package.json @@ -13,7 +13,7 @@ "lint": "NODE_NO_WARNINGS=1 eslint . --ext .ts --ignore-path ./.eslintignore --max-warnings 0" }, "dependencies": { - "@aztec/bb.js": "0.66.0", + "@aztec/bb.js": "portal:../../../../barretenberg/ts", "@noir-lang/noir_js": "workspace:*", "@noir-lang/noir_wasm": "workspace:*", "@nomicfoundation/hardhat-chai-matchers": "^2.0.0", diff --git a/noir/noir-repo/tooling/noirc_abi_wasm/build.sh b/noir/noir-repo/tooling/noirc_abi_wasm/build.sh index 16fb26e55db..c07d2d8a4c1 100755 --- a/noir/noir-repo/tooling/noirc_abi_wasm/build.sh +++ b/noir/noir-repo/tooling/noirc_abi_wasm/build.sh @@ -25,7 +25,7 @@ function run_if_available { require_command jq require_command cargo require_command wasm-bindgen -require_command wasm-opt +#require_command wasm-opt self_path=$(dirname "$(readlink -f "$0")") pname=$(cargo read-manifest | jq -r '.name') diff --git a/noir/noir-repo/yarn.lock b/noir/noir-repo/yarn.lock index 77962512b08..3c8df2b1772 100644 --- a/noir/noir-repo/yarn.lock +++ b/noir/noir-repo/yarn.lock @@ -221,9 +221,9 @@ __metadata: languageName: node linkType: hard -"@aztec/bb.js@npm:0.66.0": - version: 0.66.0 - resolution: "@aztec/bb.js@npm:0.66.0" +"@aztec/bb.js@portal:../../../../barretenberg/ts::locator=integration-tests%40workspace%3Acompiler%2Fintegration-tests": + version: 0.0.0-use.local + resolution: "@aztec/bb.js@portal:../../../../barretenberg/ts::locator=integration-tests%40workspace%3Acompiler%2Fintegration-tests" dependencies: comlink: ^4.4.1 commander: ^10.0.1 @@ -232,10 +232,9 @@ __metadata: pako: ^2.1.0 tslib: ^2.4.0 bin: - bb.js: dest/node/main.js - checksum: 7295bf6543afe1c2db795a95c7ed40806de63c77e44bb4dacb2ec6a9171d1d34749150844ab47bc2499d06676e623acb408857b6aa9da702d3c576efadb8c906 + bb.js: ./dest/node/main.js languageName: node - linkType: hard + linkType: soft "@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.10.4, @babel/code-frame@npm:^7.12.11, @babel/code-frame@npm:^7.16.0, @babel/code-frame@npm:^7.22.13, @babel/code-frame@npm:^7.23.5, @babel/code-frame@npm:^7.8.3": version: 7.23.5 @@ -14124,7 +14123,7 @@ __metadata: version: 0.0.0-use.local resolution: "integration-tests@workspace:compiler/integration-tests" dependencies: - "@aztec/bb.js": 0.66.0 + "@aztec/bb.js": "portal:../../../../barretenberg/ts" "@noir-lang/noir_js": "workspace:*" "@noir-lang/noir_wasm": "workspace:*" "@nomicfoundation/hardhat-chai-matchers": ^2.0.0