From 03224641088609f7a3fc4d514acfd96bd61c5d26 Mon Sep 17 00:00:00 2001 From: AztecBot Date: Thu, 4 Apr 2024 15:39:40 +0000 Subject: [PATCH] feat!: contract_abi-exports (https://github.com/AztecProtocol/aztec-packages/pull/5386) # Goal This PR aims to expose arbitrary types and values resulting from contract compilation in the resulting JSON artifact, in a way that is not tied to aztec-specific features or even smart contracts at all. # Problem Up until now, Noir compiled crates that used the `contract` keyword with a specific flow, which also added additional structs and metadata to the output such as whatever structs were marked with the `#[event]` attribute. This coupled Noir to smart contract specific constructs, which were propagated through the compiler (from the parser to the actual compilation output). For https://github.com/AztecProtocol/aztec-packages/issues/5079 and several other tasks that aim to reduce the mental load and improve the general devex of our users, we ***need*** to expose several other structs that are even more specific to aztec, which would only compromise the generality of the compiler further. # Proposed solution The introduction of a new attribute `#[abi(tag)]` that can be applied to both `structs` and `global` top-level statements, and export types (with the current `ABIType` format) and values (with the new `ABIValue` format) in a way that can be interpreted by components further downstream (for example, our typescript codegen). This way, the noir compiler doesn't know (or care) about whatever gets included in the artifact. The `events` contract artifact key gets replaced by: ```typescript outputs: { structs: Record; globals: Record; }; ``` # What this approach allows - Removing the smart contract specific attribute `#[event]`, replacing it by a more general `#[abi(events)]`. - Substantial devex improvements, such as exposing storage layout, note ids: ![image](https://github.com/AztecProtocol/aztec-packages/assets/5404052/dba1d6ca-1286-4d4d-912e-f222d3414f32) ...or even private function return values prior to macro processing for decoding `.view` calls https://github.com/AztecProtocol/aztec-packages/issues/2665 --------- Co-authored-by: esau <152162806+sklppy88@users.noreply.github.com> Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com> --- .aztec-sync-commit | 2 +- .github/Cross.toml | 3 +- .github/workflows/release.yml | 14 +- Cargo.lock | 46 +- aztec_macros/src/lib.rs | 20 +- aztec_macros/src/transforms/events.rs | 8 +- aztec_macros/src/transforms/functions.rs | 152 ++-- aztec_macros/src/transforms/storage.rs | 52 +- aztec_macros/src/utils/ast_utils.rs | 2 + aztec_macros/src/utils/errors.rs | 6 + compiler/noirc_driver/src/abi_gen.rs | 50 +- compiler/noirc_driver/src/contract.rs | 15 +- compiler/noirc_driver/src/lib.rs | 73 +- compiler/noirc_evaluator/Cargo.toml | 3 +- compiler/noirc_evaluator/src/ssa.rs | 35 +- .../src/ssa/opt/flatten_cfg/value_merger.rs | 4 +- compiler/noirc_frontend/Cargo.toml | 1 - compiler/noirc_frontend/build.rs | 15 - compiler/noirc_frontend/src/ast/statement.rs | 59 +- compiler/noirc_frontend/src/blns/LICENSE | 21 - compiler/noirc_frontend/src/blns/README.md | 9 - .../noirc_frontend/src/blns/blns.base64.json | 679 ------------------ compiler/noirc_frontend/src/debug/mod.rs | 13 +- .../src/hir/def_collector/dc_mod.rs | 9 +- .../noirc_frontend/src/hir/def_map/mod.rs | 52 +- .../src/hir/resolution/errors.rs | 9 + .../src/hir/resolution/resolver.rs | 44 +- .../src/hir/type_check/errors.rs | 7 +- .../noirc_frontend/src/hir/type_check/expr.rs | 136 ++-- .../noirc_frontend/src/hir/type_check/mod.rs | 91 +-- .../noirc_frontend/src/hir/type_check/stmt.rs | 44 +- compiler/noirc_frontend/src/hir_def/stmt.rs | 14 +- compiler/noirc_frontend/src/hir_def/types.rs | 29 +- compiler/noirc_frontend/src/lexer/lexer.rs | 110 --- compiler/noirc_frontend/src/lexer/token.rs | 7 +- .../src/monomorphization/errors.rs | 39 - .../src/monomorphization/mod.rs | 345 +++++---- compiler/noirc_frontend/src/node_interner.rs | 59 +- compiler/noirc_frontend/src/parser/parser.rs | 34 +- .../src/parser/parser/attributes.rs | 23 + .../src/parser/parser/structs.rs | 32 +- compiler/noirc_frontend/src/tests.rs | 12 +- compiler/wasm/src/compile.rs | 9 +- compiler/wasm/src/compile_new.rs | 2 +- compiler/wasm/src/types/noir_artifact.ts | 61 +- cspell.json | 2 - noir_stdlib/src/cmp.nr | 14 +- noir_stdlib/src/hash/poseidon2.nr | 2 +- noir_stdlib/src/ops.nr | 54 +- .../array_length_defaulting/Nargo.toml | 7 - .../array_length_defaulting/src/main.nr | 10 - .../hashmap_load_factor/Nargo.toml | 0 .../hashmap_load_factor/src/main.nr | 0 .../typevar_default/Nargo.toml | 7 - .../typevar_default/src/main.nr | 12 - .../compile_success_empty/option/src/main.nr | 4 +- .../regression_4635/Nargo.toml | 7 - .../regression_4635/src/main.nr | 59 -- .../hashmap_load_factor/Prover.toml | 23 - .../bit_shifts_runtime/src/main.nr | 2 +- .../fold_basic_nested_call/src/main.nr | 2 +- .../execution_success/prelude/src/main.nr | 4 +- .../regression_sha256_slice/Nargo.toml | 7 - .../regression_sha256_slice/Prover.toml | 1 - .../regression_sha256_slice/src/main.nr | 12 - tooling/bb_abstraction_leaks/build.rs | 2 +- tooling/debugger/ignored-tests.txt | 2 - tooling/nargo/src/artifacts/contract.rs | 24 +- tooling/nargo_cli/src/main.rs | 4 +- .../noir_js_backend_barretenberg/package.json | 2 +- tooling/noirc_abi/src/lib.rs | 62 +- tooling/noirc_abi/src/serialization.rs | 34 +- yarn.lock | 13 +- 73 files changed, 958 insertions(+), 1864 deletions(-) delete mode 100644 compiler/noirc_frontend/build.rs delete mode 100644 compiler/noirc_frontend/src/blns/LICENSE delete mode 100644 compiler/noirc_frontend/src/blns/README.md delete mode 100644 compiler/noirc_frontend/src/blns/blns.base64.json delete mode 100644 compiler/noirc_frontend/src/monomorphization/errors.rs delete mode 100644 test_programs/compile_failure/array_length_defaulting/Nargo.toml delete mode 100644 test_programs/compile_failure/array_length_defaulting/src/main.nr rename test_programs/{execution_failure => compile_failure}/hashmap_load_factor/Nargo.toml (100%) rename test_programs/{execution_failure => compile_failure}/hashmap_load_factor/src/main.nr (100%) delete mode 100644 test_programs/compile_failure/typevar_default/Nargo.toml delete mode 100644 test_programs/compile_failure/typevar_default/src/main.nr delete mode 100644 test_programs/compile_success_empty/regression_4635/Nargo.toml delete mode 100644 test_programs/compile_success_empty/regression_4635/src/main.nr delete mode 100644 test_programs/execution_failure/hashmap_load_factor/Prover.toml delete mode 100644 test_programs/execution_success/regression_sha256_slice/Nargo.toml delete mode 100644 test_programs/execution_success/regression_sha256_slice/Prover.toml delete mode 100644 test_programs/execution_success/regression_sha256_slice/src/main.nr diff --git a/.aztec-sync-commit b/.aztec-sync-commit index 540b447693c..ad2e4e57389 100644 --- a/.aztec-sync-commit +++ b/.aztec-sync-commit @@ -1 +1 @@ -bb719200034e3bc6db09fb56538dadca4203abf4 +745d5229db86b2188f52ab7ccc8f568aef8f5797 diff --git a/.github/Cross.toml b/.github/Cross.toml index 6520a288d5d..09e6316a59c 100644 --- a/.github/Cross.toml +++ b/.github/Cross.toml @@ -2,8 +2,7 @@ passthrough = [ "HOME", "RUST_BACKTRACE", - "BARRETENBERG_BIN_DIR", - "BLNS_JSON_PATH" + "BARRETENBERG_BIN_DIR" ] volumes = [ "HOME", diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index badcd3af2dd..249d83afecc 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -79,15 +79,6 @@ jobs: - name: Install Yarn dependencies uses: ./.github/actions/setup - - name: Install wasm-bindgen-cli - uses: taiki-e/install-action@v2 - with: - tool: wasm-bindgen-cli@0.2.86 - - - name: Install wasm-opt - run: | - npm i wasm-opt -g - - name: Query new noir version id: noir-version run: | @@ -116,20 +107,17 @@ jobs: if: ${{ always() }} needs: - - release-please - update-acvm-workspace-package-versions - update-docs env: # We treat any skipped or failing jobs as a failure for the workflow as a whole. - FAIL: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') || contains(needs.*.result, 'skipped') }} + FAIL: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') || contains(needs.*.result, 'skipped') } steps: - name: Add warning to sticky comment uses: marocchino/sticky-pull-request-comment@v2 with: - # We need to specify the PR on which to make the comment as workflow is triggered by push. - number: ${{ fromJSON(needs.release-please.outputs.release-pr).number }} # delete the comment in case failures have been fixed delete: ${{ !env.FAIL }} message: "The release workflow has not completed successfully. Releasing now will result in a broken release" diff --git a/Cargo.lock b/Cargo.lock index 2f85b26f974..ba0b7453576 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -542,9 +542,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.2" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" [[package]] name = "bitmaps" @@ -789,9 +789,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.37" +version = "0.4.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a0d04d43504c61aa6c7531f1871dd0d418d91130162063b789da00fd7057a5e" +checksum = "defd4e7873dbddba6c7c91e199c7fcb946abc4a6a4ac3195400bcfb01b5de877" dependencies = [ "android-tzdata", "iana-time-zone", @@ -799,7 +799,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-targets 0.52.4", + "windows-targets 0.48.1", ] [[package]] @@ -1044,9 +1044,9 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] name = "corosensei" @@ -1607,12 +1607,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.8" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.48.0", ] [[package]] @@ -2569,16 +2569,16 @@ version = "0.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3af92c55d7d839293953fcd0fda5ecfe93297cfde6ffbdec13b41d99c0ba6607" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "libc", "redox_syscall 0.4.1", ] [[package]] name = "linux-raw-sys" -version = "0.4.13" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0" [[package]] name = "lock_api" @@ -3070,7 +3070,6 @@ name = "noirc_evaluator" version = "0.26.0" dependencies = [ "acvm", - "chrono", "fxhash", "im", "iter-extended", @@ -3088,7 +3087,6 @@ version = "0.26.0" dependencies = [ "acvm", "arena", - "base64 0.21.2", "chumsky", "fm", "iter-extended", @@ -3133,7 +3131,7 @@ version = "6.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "crossbeam-channel", "filetime", "fsevent-sys", @@ -3587,7 +3585,7 @@ checksum = "7c003ac8c77cb07bb74f5f198bce836a689bcd5a42574612bf14d17bfd08c20e" dependencies = [ "bit-set", "bit-vec", - "bitflags 2.4.2", + "bitflags 2.5.0", "lazy_static", "num-traits", "rand 0.8.5", @@ -4076,15 +4074,15 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.28" +version = "0.38.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" +checksum = "0a962918ea88d644592894bc6dc55acc6c0956488adcebbfb6e273506b7fd6e5" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.48.0", ] [[package]] @@ -4556,9 +4554,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.2" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" [[package]] name = "smawk" @@ -5550,7 +5548,7 @@ version = "0.121.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9dbe55c8f9d0dbd25d9447a5a889ff90c0cc3feaa7395310d3d826b2c703eaab" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "indexmap 2.0.0", "semver", ] diff --git a/aztec_macros/src/lib.rs b/aztec_macros/src/lib.rs index 3ee6f9c21b9..56c1377d9a9 100644 --- a/aztec_macros/src/lib.rs +++ b/aztec_macros/src/lib.rs @@ -14,10 +14,7 @@ use transforms::{ use noirc_frontend::{ hir::def_collector::dc_crate::{UnresolvedFunctions, UnresolvedTraitImpl}, - macros_api::{ - CrateId, FileId, HirContext, MacroError, MacroProcessor, SecondaryAttribute, SortedModule, - Span, - }, + macros_api::{CrateId, FileId, HirContext, MacroError, MacroProcessor, SortedModule, Span}, }; use utils::{ @@ -90,15 +87,18 @@ fn transform_module(module: &mut SortedModule) -> Result let mut has_transformed_module = false; // Check for a user defined storage struct - let storage_defined = check_for_storage_definition(module); - let storage_implemented = check_for_storage_implementation(module); - if storage_defined && !storage_implemented { - generate_storage_implementation(module)?; + let maybe_storage_struct_name = check_for_storage_definition(module)?; + let storage_defined = maybe_storage_struct_name.is_some(); + + if let Some(storage_struct_name) = maybe_storage_struct_name { + if !check_for_storage_implementation(module, &storage_struct_name) { + generate_storage_implementation(module, &storage_struct_name)?; + } } - for structure in module.types.iter() { - if structure.attributes.iter().any(|attr| matches!(attr, SecondaryAttribute::Event)) { + for structure in module.types.iter_mut() { + if structure.attributes.iter().any(|attr| is_custom_attribute(attr, "aztec(event)")) { module.impls.push(generate_selector_impl(structure)); has_transformed_module = true; } diff --git a/aztec_macros/src/transforms/events.rs b/aztec_macros/src/transforms/events.rs index e7e39ed29ba..b77a5821b81 100644 --- a/aztec_macros/src/transforms/events.rs +++ b/aztec_macros/src/transforms/events.rs @@ -16,7 +16,8 @@ use crate::{ chained_dep, utils::{ ast_utils::{ - call, expression, ident, ident_path, make_statement, make_type, path, variable_path, + call, expression, ident, ident_path, is_custom_attribute, make_statement, make_type, + path, variable_path, }, constants::SIGNATURE_PLACEHOLDER, errors::AztecMacroError, @@ -38,7 +39,8 @@ use crate::{ /// This allows developers to emit events without having to write the signature of the event every time they emit it. /// The signature cannot be known at this point since types are not resolved yet, so we use a signature placeholder. /// It'll get resolved after by transforming the HIR. -pub fn generate_selector_impl(structure: &NoirStruct) -> TypeImpl { +pub fn generate_selector_impl(structure: &mut NoirStruct) -> TypeImpl { + structure.attributes.push(SecondaryAttribute::Abi("events".to_string())); let struct_type = make_type(UnresolvedTypeData::Named(path(structure.name.clone()), vec![], true)); @@ -174,7 +176,7 @@ pub fn transform_events( ) -> Result<(), (AztecMacroError, FileId)> { for struct_id in collect_crate_structs(crate_id, context) { let attributes = context.def_interner.struct_attributes(&struct_id); - if attributes.iter().any(|attr| matches!(attr, SecondaryAttribute::Event)) { + if attributes.iter().any(|attr| is_custom_attribute(attr, "aztec(event)")) { transform_event(struct_id, &mut context.def_interner)?; } } diff --git a/aztec_macros/src/transforms/functions.rs b/aztec_macros/src/transforms/functions.rs index 9844abc30fe..30c14f53e62 100644 --- a/aztec_macros/src/transforms/functions.rs +++ b/aztec_macros/src/transforms/functions.rs @@ -45,13 +45,13 @@ pub fn transform_function( // Add initialization check if insert_init_check { - let init_check = create_init_check(); + let init_check = create_init_check(ty); func.def.body.statements.insert(0, init_check); } // Add assertion for initialization arguments and sender if is_initializer { - func.def.body.statements.insert(0, create_assert_initializer()); + func.def.body.statements.insert(0, create_assert_initializer(ty)); } // Add access to the storage struct @@ -85,7 +85,7 @@ pub fn transform_function( // Before returning mark the contract as initialized if is_initializer { - let mark_initialized = create_mark_as_initialized(); + let mark_initialized = create_mark_as_initialized(ty); func.def.body.statements.push(mark_initialized); } @@ -159,9 +159,10 @@ fn create_inputs(ty: &str) -> Param { /// ```noir /// assert_is_initialized(&mut context); /// ``` -fn create_init_check() -> Statement { +fn create_init_check(ty: &str) -> Statement { + let fname = format!("assert_is_initialized_{}", ty.to_case(Case::Snake)); make_statement(StatementKind::Expression(call( - variable_path(chained_dep!("aztec", "initializer", "assert_is_initialized")), + variable_path(chained_dep!("aztec", "initializer", &fname)), vec![mutable_reference("context")], ))) } @@ -172,9 +173,10 @@ fn create_init_check() -> Statement { /// ```noir /// mark_as_initialized(&mut context); /// ``` -fn create_mark_as_initialized() -> Statement { +fn create_mark_as_initialized(ty: &str) -> Statement { + let fname = format!("mark_as_initialized_{}", ty.to_case(Case::Snake)); make_statement(StatementKind::Expression(call( - variable_path(chained_dep!("aztec", "initializer", "mark_as_initialized")), + variable_path(chained_dep!("aztec", "initializer", &fname)), vec![mutable_reference("context")], ))) } @@ -205,13 +207,11 @@ fn create_internal_check(fname: &str) -> Statement { /// ```noir /// assert_initialization_matches_address_preimage(context); /// ``` -fn create_assert_initializer() -> Statement { +fn create_assert_initializer(ty: &str) -> Statement { + let fname = + format!("assert_initialization_matches_address_preimage_{}", ty.to_case(Case::Snake)); make_statement(StatementKind::Expression(call( - variable_path(chained_dep!( - "aztec", - "initializer", - "assert_initialization_matches_address_preimage" - )), + variable_path(chained_dep!("aztec", "initializer", &fname)), vec![variable("context")], ))) } @@ -223,62 +223,66 @@ fn create_assert_initializer() -> Statement { /// ```noir /// #[aztec(private)] /// fn foo(structInput: SomeStruct, arrayInput: [u8; 10], fieldInput: Field) -> Field { -/// // Create the bounded vec object -/// let mut serialized_args = BoundedVec::new(); +/// // Create the hasher object +/// let mut hasher = Hasher::new(); /// /// // struct inputs call serialize on them to add an array of fields -/// serialized_args.extend_from_array(structInput.serialize()); +/// hasher.add_multiple(structInput.serialize()); /// -/// // Array inputs are iterated over and each element is added to the bounded vec (as a field) +/// // Array inputs are iterated over and each element is added to the hasher (as a field) /// for i in 0..arrayInput.len() { -/// serialized_args.push(arrayInput[i] as Field); +/// hasher.add(arrayInput[i] as Field); /// } -/// // Field inputs are added to the bounded vec -/// serialized_args.push({ident}); +/// // Field inputs are added to the hasher +/// hasher.add({ident}); /// /// // Create the context /// // The inputs (injected by this `create_inputs`) and completed hash object are passed to the context -/// let mut context = PrivateContext::new(inputs, hash_args(serialized_args)); +/// let mut context = PrivateContext::new(inputs, hasher.hash()); /// } /// ``` fn create_context(ty: &str, params: &[Param]) -> Result, AztecMacroError> { let mut injected_expressions: Vec = vec![]; - // `let mut serialized_args = BoundedVec::new();` - let let_serialized_args = mutable_assignment( - "serialized_args", // Assigned to + let hasher_name = "args_hasher"; + + // `let mut args_hasher = Hasher::new();` + let let_hasher = mutable_assignment( + hasher_name, // Assigned to call( - variable_path(chained_dep!("std", "collections", "bounded_vec", "BoundedVec", "new")), // Path - vec![], // args + variable_path(chained_dep!("aztec", "hash", "ArgsHasher", "new")), // Path + vec![], // args ), ); - // Completes: `let mut serialized_args = BoundedVec::new();` - injected_expressions.push(let_serialized_args); + // Completes: `let mut args_hasher = Hasher::new();` + injected_expressions.push(let_hasher); - // Iterate over each of the function parameters, adding to them to the bounded vec + // Iterate over each of the function parameters, adding to them to the hasher for Param { pattern, typ, span, .. } in params { match pattern { Pattern::Identifier(identifier) => { // Match the type to determine the padding to do let unresolved_type = &typ.typ; let expression = match unresolved_type { - // `serialized_args.extend_from_array({ident}.serialize())` - UnresolvedTypeData::Named(..) => add_struct_to_serialized_args(identifier), + // `hasher.add_multiple({ident}.serialize())` + UnresolvedTypeData::Named(..) => add_struct_to_hasher(identifier, hasher_name), UnresolvedTypeData::Array(_, arr_type) => { - add_array_to_serialized_args(identifier, arr_type) + add_array_to_hasher(identifier, arr_type, hasher_name) + } + // `hasher.add({ident})` + UnresolvedTypeData::FieldElement => { + add_field_to_hasher(identifier, hasher_name) } - // `serialized_args.push({ident})` - UnresolvedTypeData::FieldElement => add_field_to_serialized_args(identifier), - // Add the integer to the serialized args, casted to a field - // `serialized_args.push({ident} as Field)` + // Add the integer to the hasher, casted to a field + // `hasher.add({ident} as Field)` UnresolvedTypeData::Integer(..) | UnresolvedTypeData::Bool => { - add_cast_to_serialized_args(identifier) + add_cast_to_hasher(identifier, hasher_name) } UnresolvedTypeData::String(..) => { let (var_bytes, id) = str_to_bytes(identifier); injected_expressions.push(var_bytes); - add_array_to_serialized_args( + add_array_to_hasher( &id, &UnresolvedType { typ: UnresolvedTypeData::Integer( @@ -287,6 +291,7 @@ fn create_context(ty: &str, params: &[Param]) -> Result, AztecMac ), span: None, }, + hasher_name, ) } _ => { @@ -304,10 +309,11 @@ fn create_context(ty: &str, params: &[Param]) -> Result, AztecMac // Create the inputs to the context let inputs_expression = variable("inputs"); - // `hash_args(serialized_args)` - let hash_call = call( - variable_path(chained_dep!("aztec", "hash", "hash_args")), // variable - vec![variable("serialized_args")], // args + // `args_hasher.hash()` + let hash_call = method_call( + variable(hasher_name), // variable + "hash", // method name + vec![], // args ); let path_snippet = ty.to_case(Case::Snake); // e.g. private_context @@ -591,11 +597,11 @@ fn create_context_finish() -> Statement { } // -// Methods to create hash_args inputs +// Methods to create hasher inputs // -fn add_struct_to_serialized_args(identifier: &Ident) -> Statement { - // If this is a struct, we call serialize and add the array to the serialized args +fn add_struct_to_hasher(identifier: &Ident, hasher_name: &str) -> Statement { + // If this is a struct, we call serialize and add the array to the hasher let serialized_call = method_call( variable_path(path(identifier.clone())), // variable "serialize", // method name @@ -603,9 +609,9 @@ fn add_struct_to_serialized_args(identifier: &Ident) -> Statement { ); make_statement(StatementKind::Semi(method_call( - variable("serialized_args"), // variable - "extend_from_array", // method name - vec![serialized_call], // args + variable(hasher_name), // variable + "add_multiple", // method name + vec![serialized_call], // args ))) } @@ -625,7 +631,7 @@ fn str_to_bytes(identifier: &Ident) -> (Statement, Ident) { } fn create_loop_over(var: Expression, loop_body: Vec) -> Statement { - // If this is an array of primitive types (integers / fields) we can add them each to the serialized args + // If this is an array of primitive types (integers / fields) we can add them each to the hasher // casted to a field let span = var.span; @@ -638,7 +644,7 @@ fn create_loop_over(var: Expression, loop_body: Vec) -> Statement { // What will be looped over - // - `serialized_args.push({ident}[i] as Field)` + // - `hasher.add({ident}[i] as Field)` let for_loop_block = expression(ExpressionKind::Block(BlockExpression { statements: loop_body })); @@ -657,66 +663,70 @@ fn create_loop_over(var: Expression, loop_body: Vec) -> Statement { })) } -fn add_array_to_serialized_args(identifier: &Ident, arr_type: &UnresolvedType) -> Statement { - // If this is an array of primitive types (integers / fields) we can add them each to the serialized_args +fn add_array_to_hasher( + identifier: &Ident, + arr_type: &UnresolvedType, + hasher_name: &str, +) -> Statement { + // If this is an array of primitive types (integers / fields) we can add them each to the hasher // casted to a field // Wrap in the semi thing - does that mean ended with semi colon? - // `serialized_args.push({ident}[i] as Field)` + // `hasher.add({ident}[i] as Field)` let arr_index = index_array(identifier.clone(), "i"); - let (add_expression, vec_method_name) = match arr_type.typ { + let (add_expression, hasher_method_name) = match arr_type.typ { UnresolvedTypeData::Named(..) => { - let vec_method_name = "extend_from_array".to_owned(); + let hasher_method_name = "add_multiple".to_owned(); let call = method_call( // All serialize on each element arr_index, // variable "serialize", // method name vec![], // args ); - (call, vec_method_name) + (call, hasher_method_name) } _ => { - let vec_method_name = "push".to_owned(); + let hasher_method_name = "add".to_owned(); let call = cast( arr_index, // lhs - `ident[i]` UnresolvedTypeData::FieldElement, // cast to - `as Field` ); - (call, vec_method_name) + (call, hasher_method_name) } }; let block_statement = make_statement(StatementKind::Semi(method_call( - variable("serialized_args"), // variable - &vec_method_name, // method name + variable(hasher_name), // variable + &hasher_method_name, // method name vec![add_expression], ))); create_loop_over(variable_ident(identifier.clone()), vec![block_statement]) } -fn add_field_to_serialized_args(identifier: &Ident) -> Statement { - // `serialized_args.push({ident})` +fn add_field_to_hasher(identifier: &Ident, hasher_name: &str) -> Statement { + // `hasher.add({ident})` let ident = variable_path(path(identifier.clone())); make_statement(StatementKind::Semi(method_call( - variable("serialized_args"), // variable - "push", // method name - vec![ident], // args + variable(hasher_name), // variable + "add", // method name + vec![ident], // args ))) } -fn add_cast_to_serialized_args(identifier: &Ident) -> Statement { - // `serialized_args.push({ident} as Field)` +fn add_cast_to_hasher(identifier: &Ident, hasher_name: &str) -> Statement { + // `hasher.add({ident} as Field)` // `{ident} as Field` let cast_operation = cast( variable_path(path(identifier.clone())), // lhs UnresolvedTypeData::FieldElement, // rhs ); - // `serialized_args.push({ident} as Field)` + // `hasher.add({ident} as Field)` make_statement(StatementKind::Semi(method_call( - variable("serialized_args"), // variable - "push", // method name - vec![cast_operation], // args + variable(hasher_name), // variable + "add", // method name + vec![cast_operation], // args ))) } diff --git a/aztec_macros/src/transforms/storage.rs b/aztec_macros/src/transforms/storage.rs index 10f44d01bb4..ab9d8d587ab 100644 --- a/aztec_macros/src/transforms/storage.rs +++ b/aztec_macros/src/transforms/storage.rs @@ -9,15 +9,16 @@ use noirc_frontend::{ node_interner::{TraitId, TraitImplKind}, parser::SortedModule, BlockExpression, Expression, ExpressionKind, FunctionDefinition, Ident, Literal, NoirFunction, - PathKind, Pattern, StatementKind, Type, TypeImpl, UnresolvedType, UnresolvedTypeData, + NoirStruct, PathKind, Pattern, StatementKind, Type, TypeImpl, UnresolvedType, + UnresolvedTypeData, }; use crate::{ chained_dep, chained_path, utils::{ ast_utils::{ - call, expression, ident, ident_path, lambda, make_statement, make_type, pattern, - return_type, variable, variable_path, + call, expression, ident, ident_path, is_custom_attribute, lambda, make_statement, + make_type, pattern, return_type, variable, variable_path, }, errors::AztecMacroError, hir_utils::{collect_crate_structs, collect_traits}, @@ -25,15 +26,32 @@ use crate::{ }; // Check to see if the user has defined a storage struct -pub fn check_for_storage_definition(module: &SortedModule) -> bool { - module.types.iter().any(|r#struct| r#struct.name.0.contents == "Storage") +pub fn check_for_storage_definition( + module: &SortedModule, +) -> Result, AztecMacroError> { + let result: Vec<&NoirStruct> = module + .types + .iter() + .filter(|r#struct| { + r#struct.attributes.iter().any(|attr| is_custom_attribute(attr, "aztec(storage)")) + }) + .collect(); + if result.len() > 1 { + return Err(AztecMacroError::MultipleStorageDefinitions { + span: result.first().map(|res| res.name.span()), + }); + } + Ok(result.iter().map(|&r#struct| r#struct.name.0.contents.clone()).next()) } // Check to see if the user has defined a storage struct -pub fn check_for_storage_implementation(module: &SortedModule) -> bool { +pub fn check_for_storage_implementation( + module: &SortedModule, + storage_struct_name: &String, +) -> bool { module.impls.iter().any(|r#impl| match &r#impl.object_type.typ { UnresolvedTypeData::Named(path, _, _) => { - path.segments.last().is_some_and(|segment| segment.0.contents == "Storage") + path.segments.last().is_some_and(|segment| segment.0.contents == *storage_struct_name) } _ => false, }) @@ -117,9 +135,15 @@ pub fn generate_storage_field_constructor( /// /// Storage slots are generated as 0 and will be populated using the information from the HIR /// at a later stage. -pub fn generate_storage_implementation(module: &mut SortedModule) -> Result<(), AztecMacroError> { - let definition = - module.types.iter().find(|r#struct| r#struct.name.0.contents == "Storage").unwrap(); +pub fn generate_storage_implementation( + module: &mut SortedModule, + storage_struct_name: &String, +) -> Result<(), AztecMacroError> { + let definition = module + .types + .iter() + .find(|r#struct| r#struct.name.0.contents == *storage_struct_name) + .unwrap(); let slot_zero = expression(ExpressionKind::Literal(Literal::Integer( FieldElement::from(i128::from(0)), @@ -136,7 +160,7 @@ pub fn generate_storage_implementation(module: &mut SortedModule) -> Result<(), .collect(); let storage_constructor_statement = make_statement(StatementKind::Expression(expression( - ExpressionKind::constructor((chained_path!("Storage"), field_constructors)), + ExpressionKind::constructor((chained_path!(storage_struct_name), field_constructors)), ))); let init = NoirFunction::normal(FunctionDefinition::normal( @@ -157,7 +181,7 @@ pub fn generate_storage_implementation(module: &mut SortedModule) -> Result<(), let storage_impl = TypeImpl { object_type: UnresolvedType { - typ: UnresolvedTypeData::Named(chained_path!("Storage"), vec![], true), + typ: UnresolvedTypeData::Named(chained_path!(storage_struct_name), vec![], true), span: Some(Span::default()), }, type_span: Span::default(), @@ -243,7 +267,9 @@ pub fn assign_storage_slots( let interner: &mut NodeInterner = context.def_interner.borrow_mut(); let r#struct = interner.get_struct(struct_id); let file_id = r#struct.borrow().location.file; - if r#struct.borrow().name.0.contents == "Storage" && r#struct.borrow().id.krate().is_root() + let attributes = interner.struct_attributes(&struct_id); + if attributes.iter().any(|attr| is_custom_attribute(attr, "aztec(storage)")) + && r#struct.borrow().id.krate().is_root() { let init_id = interner .lookup_method( diff --git a/aztec_macros/src/utils/ast_utils.rs b/aztec_macros/src/utils/ast_utils.rs index bdcbad646c2..eb8f5a4156d 100644 --- a/aztec_macros/src/utils/ast_utils.rs +++ b/aztec_macros/src/utils/ast_utils.rs @@ -67,6 +67,7 @@ pub fn mutable_assignment(name: &str, assigned_to: Expression) -> Statement { pattern: mutable(name), r#type: make_type(UnresolvedTypeData::Unspecified), expression: assigned_to, + attributes: vec![], })) } @@ -82,6 +83,7 @@ pub fn assignment(name: &str, assigned_to: Expression) -> Statement { pattern: pattern(name), r#type: make_type(UnresolvedTypeData::Unspecified), expression: assigned_to, + attributes: vec![], })) } diff --git a/aztec_macros/src/utils/errors.rs b/aztec_macros/src/utils/errors.rs index 48186555eff..509322b3db2 100644 --- a/aztec_macros/src/utils/errors.rs +++ b/aztec_macros/src/utils/errors.rs @@ -11,6 +11,7 @@ pub enum AztecMacroError { UnsupportedStorageType { span: Option, typ: UnresolvedTypeData }, CouldNotAssignStorageSlots { secondary_message: Option }, CouldNotImplementNoteInterface { span: Option, secondary_message: Option }, + MultipleStorageDefinitions { span: Option }, EventError { span: Span, message: String }, UnsupportedAttributes { span: Span, secondary_message: Option }, } @@ -46,6 +47,11 @@ impl From for MacroError { AztecMacroError::CouldNotImplementNoteInterface { span, secondary_message } => MacroError { primary_message: "Could not implement automatic methods for note, please provide an implementation of the NoteInterface trait".to_string(), secondary_message, + span + }, + AztecMacroError::MultipleStorageDefinitions { span } => MacroError { + primary_message: "Only one struct can be tagged as #[aztec(storage)]".to_string(), + secondary_message: None, span, }, AztecMacroError::EventError { span, message } => MacroError { diff --git a/compiler/noirc_driver/src/abi_gen.rs b/compiler/noirc_driver/src/abi_gen.rs index 7fafa719186..516c8a53cb6 100644 --- a/compiler/noirc_driver/src/abi_gen.rs +++ b/compiler/noirc_driver/src/abi_gen.rs @@ -2,10 +2,11 @@ use std::collections::BTreeMap; use acvm::acir::native_types::Witness; use iter_extended::{btree_map, vecmap}; -use noirc_abi::{Abi, AbiParameter, AbiReturnType, AbiType}; +use noirc_abi::{Abi, AbiParameter, AbiReturnType, AbiType, AbiValue}; use noirc_frontend::{ hir::Context, - hir_def::{function::Param, stmt::HirPattern}, + hir_def::{expr::HirArrayLiteral, function::Param, stmt::HirPattern}, + macros_api::{HirExpression, HirLiteral}, node_interner::{FuncId, NodeInterner}, Visibility, }; @@ -109,6 +110,51 @@ fn collapse_ranges(witnesses: &[Witness]) -> Vec> { wit } +pub(super) fn value_from_hir_expression(context: &Context, expression: HirExpression) -> AbiValue { + match expression { + HirExpression::Constructor(constructor) => { + let fields = constructor + .fields + .iter() + .map(|(ident, expr_id)| { + ( + ident.0.contents.to_string(), + value_from_hir_expression( + context, + context.def_interner.expression(expr_id), + ), + ) + }) + .collect(); + AbiValue::Struct { fields } + } + HirExpression::Literal(literal) => match literal { + HirLiteral::Array(hir_array) => match hir_array { + HirArrayLiteral::Standard(expr_ids) => { + let value = expr_ids + .iter() + .map(|expr_id| { + value_from_hir_expression( + context, + context.def_interner.expression(expr_id), + ) + }) + .collect(); + AbiValue::Array { value } + } + _ => unreachable!("Repeated arrays cannot be used in the abi"), + }, + HirLiteral::Bool(value) => AbiValue::Boolean { value }, + HirLiteral::Str(value) => AbiValue::String { value }, + HirLiteral::Integer(field, sign) => { + AbiValue::Integer { value: field.to_string(), sign } + } + _ => unreachable!("Literal cannot be used in the abi"), + }, + _ => unreachable!("Type cannot be used in the abi"), + } +} + #[cfg(test)] mod test { use std::ops::Range; diff --git a/compiler/noirc_driver/src/contract.rs b/compiler/noirc_driver/src/contract.rs index 9a0e25a321b..5c0f2f81b1e 100644 --- a/compiler/noirc_driver/src/contract.rs +++ b/compiler/noirc_driver/src/contract.rs @@ -1,14 +1,20 @@ use serde::{Deserialize, Serialize}; -use std::collections::BTreeMap; +use std::collections::{BTreeMap, HashMap}; use acvm::acir::circuit::Program; use fm::FileId; -use noirc_abi::{Abi, ContractEvent}; +use noirc_abi::{Abi, AbiType, AbiValue}; use noirc_errors::debug_info::DebugInfo; use noirc_evaluator::errors::SsaReport; use super::debug::DebugFile; +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct CompiledContractOutputs { + pub structs: HashMap>, + pub globals: HashMap>, +} + #[derive(Clone, Debug, Serialize, Deserialize)] pub struct CompiledContract { pub noir_version: String, @@ -19,10 +25,7 @@ pub struct CompiledContract { /// stored in this `Vector`. pub functions: Vec, - /// All the events defined inside the contract scope. - /// An event is a struct value that can be emitted via oracles - /// by any contract function during execution. - pub events: Vec, + pub outputs: CompiledContractOutputs, pub file_map: BTreeMap, pub warnings: Vec, diff --git a/compiler/noirc_driver/src/lib.rs b/compiler/noirc_driver/src/lib.rs index 86d4cd1510d..6aff9a44c94 100644 --- a/compiler/noirc_driver/src/lib.rs +++ b/compiler/noirc_driver/src/lib.rs @@ -3,11 +3,12 @@ #![warn(unreachable_pub)] #![warn(clippy::semicolon_if_nothing_returned)] +use abi_gen::value_from_hir_expression; use acvm::acir::circuit::ExpressionWidth; use clap::Args; use fm::{FileId, FileManager}; use iter_extended::vecmap; -use noirc_abi::{AbiParameter, AbiType, ContractEvent}; +use noirc_abi::{AbiParameter, AbiType, AbiValue}; use noirc_errors::{CustomDiagnostic, FileDiagnostic}; use noirc_evaluator::create_program; use noirc_evaluator::errors::RuntimeError; @@ -16,9 +17,7 @@ use noirc_frontend::graph::{CrateId, CrateName}; use noirc_frontend::hir::def_map::{Contract, CrateDefMap}; use noirc_frontend::hir::Context; use noirc_frontend::macros_api::MacroProcessor; -use noirc_frontend::monomorphization::{ - errors::MonomorphizationError, monomorphize, monomorphize_debug, -}; +use noirc_frontend::monomorphization::{monomorphize, monomorphize_debug, MonomorphizationError}; use noirc_frontend::node_interner::FuncId; use noirc_frontend::token::SecondaryAttribute; use std::path::Path; @@ -33,7 +32,7 @@ mod stdlib; use debug::filter_relevant_files; -pub use contract::{CompiledContract, ContractFunction}; +pub use contract::{CompiledContract, CompiledContractOutputs, ContractFunction}; pub use debug::DebugFile; pub use program::CompiledProgram; @@ -70,10 +69,6 @@ pub struct CompileOptions { #[arg(long)] pub print_acir: bool, - /// Pretty print benchmark times of each code generation pass - #[arg(long, hide = true)] - pub benchmark_codegen: bool, - /// Treat all warnings as errors #[arg(long, conflicts_with = "silence_warnings")] pub deny_warnings: bool, @@ -430,18 +425,51 @@ fn compile_contract_inner( let debug_infos: Vec<_> = functions.iter().map(|function| function.debug.clone()).collect(); let file_map = filter_relevant_files(&debug_infos, &context.file_manager); + let out_structs = contract + .outputs + .structs + .into_iter() + .map(|(tag, structs)| { + let structs = structs + .into_iter() + .map(|struct_id| { + let typ = context.def_interner.get_struct(struct_id); + let typ = typ.borrow(); + let fields = vecmap(typ.get_fields(&[]), |(name, typ)| { + (name, AbiType::from_type(context, &typ)) + }); + let path = + context.fully_qualified_struct_path(context.root_crate_id(), typ.id); + AbiType::Struct { path, fields } + }) + .collect(); + (tag.to_string(), structs) + }) + .collect(); + + let out_globals = contract + .outputs + .globals + .iter() + .map(|(tag, globals)| { + let globals: Vec = globals + .iter() + .map(|global_id| { + let let_statement = + context.def_interner.get_global_let_statement(*global_id).unwrap(); + let hir_expression = + context.def_interner.expression(&let_statement.expression); + value_from_hir_expression(context, hir_expression) + }) + .collect(); + (tag.to_string(), globals) + }) + .collect(); + Ok(CompiledContract { name: contract.name, - events: contract - .events - .iter() - .map(|event_id| { - let typ = context.def_interner.get_struct(*event_id); - let typ = typ.borrow(); - ContractEvent::from_struct_type(context, &typ) - }) - .collect(), functions, + outputs: CompiledContractOutputs { structs: out_structs, globals: out_globals }, file_map, noir_version: NOIR_ARTIFACT_VERSION_STRING.to_string(), warnings, @@ -485,13 +513,8 @@ pub fn compile_no_check( } let visibility = program.return_visibility; - let (program, debug, warnings, input_witnesses, return_witnesses) = create_program( - program, - options.show_ssa, - options.show_brillig, - options.force_brillig, - options.benchmark_codegen, - )?; + let (program, debug, warnings, input_witnesses, return_witnesses) = + create_program(program, options.show_ssa, options.show_brillig, options.force_brillig)?; let abi = abi_gen::gen_abi(context, &main_function, input_witnesses, return_witnesses, visibility); diff --git a/compiler/noirc_evaluator/Cargo.toml b/compiler/noirc_evaluator/Cargo.toml index fad7c3c309e..a8f0e8d83a9 100644 --- a/compiler/noirc_evaluator/Cargo.toml +++ b/compiler/noirc_evaluator/Cargo.toml @@ -17,5 +17,4 @@ thiserror.workspace = true num-bigint = "0.4" im = { version = "15.1", features = ["serde"] } serde.workspace = true -tracing.workspace = true -chrono = "0.4.37" \ No newline at end of file +tracing.workspace = true \ No newline at end of file diff --git a/compiler/noirc_evaluator/src/ssa.rs b/compiler/noirc_evaluator/src/ssa.rs index 59f2bdc6f84..f05a0932f23 100644 --- a/compiler/noirc_evaluator/src/ssa.rs +++ b/compiler/noirc_evaluator/src/ssa.rs @@ -38,16 +38,15 @@ pub mod ssa_gen; /// convert the final SSA into ACIR and return it. pub(crate) fn optimize_into_acir( program: Program, - print_passes: bool, + print_ssa_passes: bool, print_brillig_trace: bool, force_brillig_output: bool, - print_timings: bool, ) -> Result, RuntimeError> { let abi_distinctness = program.return_distinctness; let ssa_gen_span = span!(Level::TRACE, "ssa_generation"); let ssa_gen_span_guard = ssa_gen_span.enter(); - let ssa = SsaBuilder::new(program, print_passes, force_brillig_output, print_timings)? + let ssa = SsaBuilder::new(program, print_ssa_passes, force_brillig_output)? .run_pass(Ssa::defunctionalize, "After Defunctionalization:") .run_pass(Ssa::remove_paired_rc, "After Removing Paired rc_inc & rc_decs:") .run_pass(Ssa::inline_functions, "After Inlining:") @@ -65,28 +64,13 @@ pub(crate) fn optimize_into_acir( .run_pass(Ssa::dead_instruction_elimination, "After Dead Instruction Elimination:") .finish(); - let brillig = time("SSA to Brillig", print_timings, || ssa.to_brillig(print_brillig_trace)); + let brillig = ssa.to_brillig(print_brillig_trace); drop(ssa_gen_span_guard); let last_array_uses = ssa.find_last_array_uses(); - time("SSA to ACIR", print_timings, || { - ssa.into_acir(&brillig, abi_distinctness, &last_array_uses) - }) -} - -// Helper to time SSA passes -fn time(name: &str, print_timings: bool, f: impl FnOnce() -> T) -> T { - let start_time = chrono::Utc::now().time(); - let result = f(); - - if print_timings { - let end_time = chrono::Utc::now().time(); - println!("{name}: {} ms", (end_time - start_time).num_milliseconds()); - } - - result + ssa.into_acir(&brillig, abi_distinctness, &last_array_uses) } /// Compiles the [`Program`] into [`ACIR``][acvm::acir::circuit::Program]. @@ -99,7 +83,6 @@ pub fn create_program( enable_ssa_logging: bool, enable_brillig_logging: bool, force_brillig_output: bool, - print_codegen_timings: bool, ) -> Result<(AcirProgram, Vec, Vec, Vec, Vec), RuntimeError> { let debug_variables = program.debug_variables.clone(); @@ -114,7 +97,6 @@ pub fn create_program( enable_ssa_logging, enable_brillig_logging, force_brillig_output, - print_codegen_timings, )?; assert_eq!( generated_acirs.len(), @@ -144,6 +126,7 @@ pub fn create_program( debug_infos.push(debug_info); warning_infos.extend(warnings); if is_main { + // main_input_witness = circuit.re main_input_witnesses = input_witnesses; main_return_witnesses = return_witnesses; } @@ -246,7 +229,6 @@ fn split_public_and_private_inputs( struct SsaBuilder { ssa: Ssa, print_ssa_passes: bool, - print_codegen_timings: bool, } impl SsaBuilder { @@ -254,10 +236,9 @@ impl SsaBuilder { program: Program, print_ssa_passes: bool, force_brillig_runtime: bool, - print_codegen_timings: bool, ) -> Result { let ssa = ssa_gen::generate_ssa(program, force_brillig_runtime)?; - Ok(SsaBuilder { print_ssa_passes, print_codegen_timings, ssa }.print("Initial SSA:")) + Ok(SsaBuilder { print_ssa_passes, ssa }.print("Initial SSA:")) } fn finish(self) -> Ssa { @@ -266,7 +247,7 @@ impl SsaBuilder { /// Runs the given SSA pass and prints the SSA afterward if `print_ssa_passes` is true. fn run_pass(mut self, pass: fn(Ssa) -> Ssa, msg: &str) -> Self { - self.ssa = time(msg, self.print_codegen_timings, || pass(self.ssa)); + self.ssa = pass(self.ssa); self.print(msg) } @@ -276,7 +257,7 @@ impl SsaBuilder { pass: fn(Ssa) -> Result, msg: &str, ) -> Result { - self.ssa = time(msg, self.print_codegen_timings, || pass(self.ssa))?; + self.ssa = pass(self.ssa)?; Ok(self.print(msg)) } diff --git a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs index 0a351148fa3..6b923a2e42d 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs @@ -234,9 +234,9 @@ impl<'a> ValueMerger<'a> { /// such as with dynamic indexing of non-homogenous slices. fn make_slice_dummy_data(&mut self, typ: &Type) -> ValueId { match typ { - Type::Numeric(numeric_type) => { + Type::Numeric(_) => { let zero = FieldElement::zero(); - self.dfg.make_constant(zero, Type::Numeric(*numeric_type)) + self.dfg.make_constant(zero, Type::field()) } Type::Array(element_types, len) => { let mut array = im::Vector::new(); diff --git a/compiler/noirc_frontend/Cargo.toml b/compiler/noirc_frontend/Cargo.toml index 03b92e15032..a3a8d460572 100644 --- a/compiler/noirc_frontend/Cargo.toml +++ b/compiler/noirc_frontend/Cargo.toml @@ -26,7 +26,6 @@ tracing.workspace = true petgraph = "0.6" [dev-dependencies] -base64.workspace = true strum = "0.24" strum_macros = "0.24" tempfile.workspace = true diff --git a/compiler/noirc_frontend/build.rs b/compiler/noirc_frontend/build.rs deleted file mode 100644 index 53ae9489168..00000000000 --- a/compiler/noirc_frontend/build.rs +++ /dev/null @@ -1,15 +0,0 @@ -use std::path::PathBuf; - -const BLNS_JSON_PATH: &str = "BLNS_JSON_PATH"; - -fn main() -> Result<(), String> { - let out_dir = std::env::var("OUT_DIR").unwrap(); - - let dest_path = PathBuf::from(out_dir.clone()).join("blns.base64.json"); - let dest_path_str = dest_path.to_str().unwrap(); - - println!("cargo:rustc-env={BLNS_JSON_PATH}={dest_path_str}"); - std::fs::copy("./src/blns/blns.base64.json", dest_path).unwrap(); - - Ok(()) -} diff --git a/compiler/noirc_frontend/src/ast/statement.rs b/compiler/noirc_frontend/src/ast/statement.rs index dea9fc0f3d3..aaa05af932a 100644 --- a/compiler/noirc_frontend/src/ast/statement.rs +++ b/compiler/noirc_frontend/src/ast/statement.rs @@ -2,6 +2,7 @@ use std::fmt::Display; use std::sync::atomic::{AtomicU32, Ordering}; use crate::lexer::token::SpannedToken; +use crate::macros_api::SecondaryAttribute; use crate::parser::{ParserError, ParserErrorReason}; use crate::token::Token; use crate::{ @@ -107,7 +108,7 @@ impl StatementKind { pub fn new_let( ((pattern, r#type), expression): ((Pattern, UnresolvedType), Expression), ) -> StatementKind { - StatementKind::Let(LetStatement { pattern, r#type, expression }) + StatementKind::Let(LetStatement { pattern, r#type, expression, attributes: vec![] }) } /// Create a Statement::Assign value, desugaring any combined operators like += if needed. @@ -120,7 +121,7 @@ impl StatementKind { // Desugar `a = b` to `a = a b`. This relies on the evaluation of `a` having no side effects, // which is currently enforced by the restricted syntax of LValues. if operator != Token::Assign { - let lvalue_expr = lvalue.as_expression(); + let lvalue_expr = lvalue.as_expression(span); let error_msg = "Token passed to Statement::assign is not a binary operator"; let infix = crate::InfixExpression { @@ -405,13 +406,17 @@ pub struct LetStatement { pub pattern: Pattern, pub r#type: UnresolvedType, pub expression: Expression, + pub attributes: Vec, } impl LetStatement { pub fn new_let( - ((pattern, r#type), expression): ((Pattern, UnresolvedType), Expression), + (((pattern, r#type), expression), attributes): ( + ((Pattern, UnresolvedType), Expression), + Vec, + ), ) -> LetStatement { - LetStatement { pattern, r#type, expression } + LetStatement { pattern, r#type, expression, attributes } } } @@ -425,9 +430,9 @@ pub struct AssignStatement { #[derive(Debug, PartialEq, Eq, Clone)] pub enum LValue { Ident(Ident), - MemberAccess { object: Box, field_name: Ident, span: Span }, - Index { array: Box, index: Expression, span: Span }, - Dereference(Box, Span), + MemberAccess { object: Box, field_name: Ident }, + Index { array: Box, index: Expression }, + Dereference(Box), } #[derive(Debug, PartialEq, Eq, Clone)] @@ -484,40 +489,28 @@ impl Recoverable for Pattern { } impl LValue { - fn as_expression(&self) -> Expression { + fn as_expression(&self, span: Span) -> Expression { let kind = match self { LValue::Ident(ident) => ExpressionKind::Variable(Path::from_ident(ident.clone())), - LValue::MemberAccess { object, field_name, span: _ } => { + LValue::MemberAccess { object, field_name } => { ExpressionKind::MemberAccess(Box::new(MemberAccessExpression { - lhs: object.as_expression(), + lhs: object.as_expression(span), rhs: field_name.clone(), })) } - LValue::Index { array, index, span: _ } => { - ExpressionKind::Index(Box::new(IndexExpression { - collection: array.as_expression(), - index: index.clone(), - })) - } - LValue::Dereference(lvalue, _span) => { + LValue::Index { array, index } => ExpressionKind::Index(Box::new(IndexExpression { + collection: array.as_expression(span), + index: index.clone(), + })), + LValue::Dereference(lvalue) => { ExpressionKind::Prefix(Box::new(crate::PrefixExpression { operator: crate::UnaryOp::Dereference { implicitly_added: false }, - rhs: lvalue.as_expression(), + rhs: lvalue.as_expression(span), })) } }; - let span = self.span(); Expression::new(kind, span) } - - pub fn span(&self) -> Span { - match self { - LValue::Ident(ident) => ident.span(), - LValue::MemberAccess { span, .. } - | LValue::Index { span, .. } - | LValue::Dereference(_, span) => *span, - } - } } #[derive(Debug, PartialEq, Eq, Clone)] @@ -568,6 +561,7 @@ impl ForRange { pattern: Pattern::Identifier(array_ident.clone()), r#type: UnresolvedType::unspecified(), expression: array, + attributes: vec![], }), span: array_span, }; @@ -610,6 +604,7 @@ impl ForRange { pattern: Pattern::Identifier(identifier), r#type: UnresolvedType::unspecified(), expression: Expression::new(loop_element, array_span), + attributes: vec![], }), span: array_span, }; @@ -687,11 +682,9 @@ impl Display for LValue { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { LValue::Ident(ident) => ident.fmt(f), - LValue::MemberAccess { object, field_name, span: _ } => { - write!(f, "{object}.{field_name}") - } - LValue::Index { array, index, span: _ } => write!(f, "{array}[{index}]"), - LValue::Dereference(lvalue, _span) => write!(f, "*{lvalue}"), + LValue::MemberAccess { object, field_name } => write!(f, "{object}.{field_name}"), + LValue::Index { array, index } => write!(f, "{array}[{index}]"), + LValue::Dereference(lvalue) => write!(f, "*{lvalue}"), } } } diff --git a/compiler/noirc_frontend/src/blns/LICENSE b/compiler/noirc_frontend/src/blns/LICENSE deleted file mode 100644 index 4ab5bbd793b..00000000000 --- a/compiler/noirc_frontend/src/blns/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015-2020 Max Woolf - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/compiler/noirc_frontend/src/blns/README.md b/compiler/noirc_frontend/src/blns/README.md deleted file mode 100644 index 201ed68aef0..00000000000 --- a/compiler/noirc_frontend/src/blns/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# BLNS - -[Big List of Naughty Strings](https://github.com/minimaxir/big-list-of-naughty-strings) - -## Updating - -```bash -wget -O blns.base64.json "https://raw.githubusercontent.com/minimaxir/big-list-of-naughty-strings/master/blns.base64.json" -``` diff --git a/compiler/noirc_frontend/src/blns/blns.base64.json b/compiler/noirc_frontend/src/blns/blns.base64.json deleted file mode 100644 index 18e61c0d2c4..00000000000 --- a/compiler/noirc_frontend/src/blns/blns.base64.json +++ /dev/null @@ -1,679 +0,0 @@ -[ - "", - "dW5kZWZpbmVk", - "dW5kZWY=", - "bnVsbA==", - "TlVMTA==", - "KG51bGwp", - "bmls", - "TklM", - "dHJ1ZQ==", - "ZmFsc2U=", - "VHJ1ZQ==", - "RmFsc2U=", - "VFJVRQ==", - "RkFMU0U=", - "Tm9uZQ==", - "aGFzT3duUHJvcGVydHk=", - "XA==", - "MA==", - "MQ==", - "MS4wMA==", - "JDEuMDA=", - "MS8y", - "MUUy", - "MUUwMg==", - "MUUrMDI=", - "LTE=", - "LTEuMDA=", - "LSQxLjAw", - "LTEvMg==", - "LTFFMg==", - "LTFFMDI=", - "LTFFKzAy", - "MS8w", - "MC8w", - "LTIxNDc0ODM2NDgvLTE=", - "LTkyMjMzNzIwMzY4NTQ3NzU4MDgvLTE=", - "LTA=", - "LTAuMA==", - "KzA=", - "KzAuMA==", - "MC4wMA==", - "MC4uMA==", - "Lg==", - "MC4wLjA=", - "MCwwMA==", - "MCwsMA==", - "LA==", - "MCwwLDA=", - "MC4wLzA=", - "MS4wLzAuMA==", - "MC4wLzAuMA==", - "MSwwLzAsMA==", - "MCwwLzAsMA==", - "LS0x", - "LQ==", - "LS4=", - "LSw=", - "OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5", - "OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5", - "TmFO", - "SW5maW5pdHk=", - "LUluZmluaXR5", - "SU5G", - "MSNJTkY=", - "LTEjSU5E", - "MSNRTkFO", - "MSNTTkFO", - "MSNJTkQ=", - "MHgw", - "MHhmZmZmZmZmZg==", - "MHhmZmZmZmZmZmZmZmZmZmZm", - "MHhhYmFkMWRlYQ==", - "MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5", - "MSwwMDAuMDA=", - "MSAwMDAuMDA=", - "MScwMDAuMDA=", - "MSwwMDAsMDAwLjAw", - "MSAwMDAgMDAwLjAw", - "MScwMDAnMDAwLjAw", - "MS4wMDAsMDA=", - "MSAwMDAsMDA=", - "MScwMDAsMDA=", - "MS4wMDAuMDAwLDAw", - "MSAwMDAgMDAwLDAw", - "MScwMDAnMDAwLDAw", - "MDEwMDA=", - "MDg=", - "MDk=", - "Mi4yMjUwNzM4NTg1MDcyMDExZS0zMDg=", - "LC4vOydbXS09", - "PD4/OiJ7fXxfKw==", - "IUAjJCVeJiooKWB+", - "AQIDBAUGBwgODxAREhMUFRYXGBkaGxwdHh9/", - "woDCgcKCwoPChMKGwofCiMKJworCi8KMwo3CjsKPwpDCkcKSwpPClMKVwpbCl8KYwpnCmsKbwpzC", - "ncKewp8=", - "CwwgwoXCoOGagOKAgOKAgeKAguKAg+KAhOKAheKAhuKAh+KAiOKAieKAiuKAi+KAqOKAqeKAr+KB", - "n+OAgA==", - "wq3YgNiB2ILYg9iE2IXYnNud3I/hoI7igIvigIzigI3igI7igI/igKrigKvigKzigK3igK7igaDi", - "gaHigaLigaPigaTigabigafigajiganigarigavigaziga3iga7iga/vu7/vv7nvv7rvv7vwkYK9", - "8JuyoPCbsqHwm7Ki8Juyo/CdhbPwnYW08J2FtfCdhbbwnYW38J2FuPCdhbnwnYW686CAgfOggKDz", - "oICh86CAovOggKPzoICk86CApfOggKbzoICn86CAqPOggKnzoICq86CAq/OggKzzoICt86CArvOg", - "gK/zoICw86CAsfOggLLzoICz86CAtPOggLXzoIC286CAt/OggLjzoIC586CAuvOggLvzoIC886CA", - "vfOggL7zoIC/86CBgPOggYHzoIGC86CBg/OggYTzoIGF86CBhvOggYfzoIGI86CBifOggYrzoIGL", - "86CBjPOggY3zoIGO86CBj/OggZDzoIGR86CBkvOggZPzoIGU86CBlfOggZbzoIGX86CBmPOggZnz", - "oIGa86CBm/OggZzzoIGd86CBnvOggZ/zoIGg86CBofOggaLzoIGj86CBpPOggaXzoIGm86CBp/Og", - "gajzoIGp86CBqvOggavzoIGs86CBrfOgga7zoIGv86CBsPOggbHzoIGy86CBs/OggbTzoIG186CB", - "tvOggbfzoIG486CBufOggbrzoIG786CBvPOggb3zoIG+86CBvw==", - "77u/", - "77++", - "zqniiYjDp+KImuKIq8ucwrXiiaTiiaXDtw==", - "w6XDn+KIgsaSwqnLmeKIhsuawqzigKbDpg==", - "xZPiiJHCtMKu4oCgwqXCqMuGw7jPgOKAnOKAmA==", - "wqHihKLCo8Ki4oiewqfCtuKAosKqwrrigJPiiaA=", - "wrjLm8OH4peKxLHLnMOCwq/LmMK/", - "w4XDjcOOw4/LncOTw5Tvo7/DksOaw4bimIM=", - "xZLigJ7CtOKAsMuHw4HCqMuGw5jiiI/igJ3igJk=", - "YOKBhOKCrOKAueKAuu+sge+sguKAocKwwrfigJrigJTCsQ==", - "4oWb4oWc4oWd4oWe", - "0IHQgtCD0ITQhdCG0IfQiNCJ0IrQi9CM0I3QjtCP0JDQkdCS0JPQlNCV0JbQl9CY0JnQmtCb0JzQ", - "ndCe0J/QoNCh0KLQo9Ck0KXQptCn0KjQqdCq0KvQrNCt0K7Qr9Cw0LHQstCz0LTQtdC20LfQuNC5", - "0LrQu9C80L3QvtC/0YDRgdGC0YPRhNGF0YbRh9GI0YnRitGL0YzRjdGO0Y8=", - "2aDZodmi2aPZpNml2abZp9mo2ak=", - "4oGw4oG04oG1", - "4oKA4oKB4oKC", - "4oGw4oG04oG14oKA4oKB4oKC", - "4LiU4LmJ4LmJ4LmJ4LmJ4LmJ4LmH4LmH4LmH4LmH4LmH4LmJ4LmJ4LmJ4LmJ4LmJ4LmH4LmH4LmH", - "4LmH4LmH4LmJ4LmJ4LmJ4LmJ4LmJ4LmJ4LmJ4LmJ4LmH4LmH4LmH4LmH4LmH4LmJ4LmJ4LmJ4LmJ", - "4LmJ4LmH4LmH4LmH4LmH4LmH4LmJ4LmJ4LmJ4LmJ4LmJ4LmJ4LmJ4LmJ4LmH4LmH4LmH4LmH4LmH", - "4LmJ4LmJ4LmJ4LmJ4LmJ4LmH4LmH4LmH4LmH4LmH4LmJ4LmJ4LmJ4LmJ4LmJ4LmJ4LmJ4LmJ4LmH", - "4LmH4LmH4LmH4LmH4LmJ4LmJ4LmJ4LmJ4LmJ4LmH4LmH4LmH4LmHIOC4lOC5ieC5ieC5ieC5ieC5", - "ieC5h+C5h+C5h+C5h+C5h+C5ieC5ieC5ieC5ieC5ieC5h+C5h+C5h+C5h+C5h+C5ieC5ieC5ieC5", - "ieC5ieC5ieC5ieC5ieC5h+C5h+C5h+C5h+C5h+C5ieC5ieC5ieC5ieC5ieC5h+C5h+C5h+C5h+C5", - "h+C5ieC5ieC5ieC5ieC5ieC5ieC5ieC5ieC5h+C5h+C5h+C5h+C5h+C5ieC5ieC5ieC5ieC5ieC5", - "h+C5h+C5h+C5h+C5h+C5ieC5ieC5ieC5ieC5ieC5ieC5ieC5ieC5h+C5h+C5h+C5h+C5h+C5ieC5", - "ieC5ieC5ieC5ieC5h+C5h+C5h+C5hyDguJTguYnguYnguYnguYnguYnguYfguYfguYfguYfguYfg", - "uYnguYnguYnguYnguYnguYfguYfguYfguYfguYfguYnguYnguYnguYnguYnguYnguYnguYnguYfg", - "uYfguYfguYfguYfguYnguYnguYnguYnguYnguYfguYfguYfguYfguYfguYnguYnguYnguYnguYng", - "uYnguYnguYnguYfguYfguYfguYfguYfguYnguYnguYnguYnguYnguYfguYfguYfguYfguYfguYng", - "uYnguYnguYnguYnguYnguYnguYnguYfguYfguYfguYfguYfguYnguYnguYnguYnguYnguYfguYfg", - "uYfguYc=", - "Jw==", - "Ig==", - "Jyc=", - "IiI=", - "JyIn", - "IicnJyciJyI=", - "IiciJyInJycnIg==", - "PGZvbyB2YWw94oCcYmFy4oCdIC8+", - "PGZvbyB2YWw94oCcYmFy4oCdIC8+", - "PGZvbyB2YWw94oCdYmFy4oCcIC8+", - "PGZvbyB2YWw9YGJhcicgLz4=", - "55Sw5Lit44GV44KT44Gr44GC44GS44Gm5LiL44GV44GE", - "44OR44O844OG44Kj44O844G46KGM44GL44Gq44GE44GL", - "5ZKM6KO95ryi6Kqe", - "6YOo6JC95qC8", - "7IKs7ZqM6rO87ZWZ7JuQIOyWtO2VmeyXsOq1rOyGjA==", - "7LCm7LCo66W8IO2DgOqzoCDsmKgg7Y6y7Iuc66eo6rO8IOyRm+uLpOumrCDrmKDrsKnqsIHtlZg=", - "56S+5pyD56eR5a246Zmi6Kqe5a2456CU56m25omA", - "7Jq4656A67CU7Yag66W0", - "8KCcjvCgnLHwoJ258KCxk/CgsbjwoLKW8KCzjw==", - "6KGo44Od44GCQem3l8WSw6nvvKLpgI3DnMOfwqrEhcOx5LiC45CA8KCAgA==", - "44O94Ly84LqI2YTNnOC6iOC8ve++iSDjg73gvLzguojZhM2c4LqI4Ly9776J", - "KO+9oeKXlSDiiIAg4peV772hKQ==", - "772A772oKMK04oiA772A4oip", - "X1/vvpsoLF8sKik=", - "44O7KO+/o+KIgO+/oynjg7s6Kjo=", - "776f772l4py/44O+4pWyKO+9oeKXleKAv+KXle+9oSnilbHinL/vvaXvvp8=", - "LOOAguODuzoqOuODu+OCnOKAmSgg4pi7IM+JIOKYuyAp44CC44O7Oio644O744Kc4oCZ", - "KOKVr8Kw4pahwrDvvInila/vuLUg4pS74pSB4pS7KQ==", - "KO++ieCypeebiuCype+8ie++ie+7vyDilLvilIHilLs=", - "4pSs4pSA4pSs44OOKCDCuiBfIMK644OOKQ==", - "KCDNocKwIM2cypYgzaHCsCk=", - "8J+YjQ==", - "8J+RqfCfj70=", - "8J+RqOKAjfCfprAg8J+RqPCfj7/igI3wn6awIPCfkajigI3wn6axIPCfkajwn4+/4oCN8J+msSDwn6a58J+Pv+KAjeKZgu+4jw==", - "8J+RviDwn5mHIPCfkoEg8J+ZhSDwn5mGIPCfmYsg8J+ZjiDwn5mN", - "8J+QtSDwn5mIIPCfmYkg8J+Zig==", - "4p2k77iPIPCfkpQg8J+SjCDwn5KVIPCfkp4g8J+SkyDwn5KXIPCfkpYg8J+SmCDwn5KdIPCfkp8g", - "8J+SnCDwn5KbIPCfkpog8J+SmQ==", - "4pyL8J+PvyDwn5Kq8J+PvyDwn5GQ8J+PvyDwn5mM8J+PvyDwn5GP8J+PvyDwn5mP8J+Pvw==", - "8J+aviDwn4aSIPCfhpMg8J+GlSDwn4aWIPCfhpcg8J+GmSDwn4+n", - "MO+4j+KDoyAx77iP4oOjIDLvuI/ig6MgM++4j+KDoyA077iP4oOjIDXvuI/ig6MgNu+4j+KDoyA3", - "77iP4oOjIDjvuI/ig6MgOe+4j+KDoyDwn5Sf", - "8J+HuvCfh7jwn4e38J+HuvCfh7gg8J+HpvCfh6vwn4em8J+HsvCfh7g=", - "8J+HuvCfh7jwn4e38J+HuvCfh7jwn4em8J+Hq/Cfh6bwn4ey", - "8J+HuvCfh7jwn4e38J+HuvCfh7jwn4em", - "77yR77yS77yT", - "2aHZotmj", - "2KvZhSDZhtmB2LMg2LPZgti32Kog2YjYqNin2YTYqtit2K/Zitiv2IwsINis2LLZitix2KrZiiDY", - "qNin2LPYqtiu2K/Yp9mFINij2YYg2K/ZhtmILiDYpdiwINmH2YbYp9ifINin2YTYs9iq2KfYsSDZ", - "iNiq2YbYtdmK2Kgg2YPYp9mGLiDYo9mH2ZHZhCDYp9mK2LfYp9mE2YrYp9iMINio2LHZiti32KfZ", - "htmK2Kct2YHYsdmG2LPYpyDZgtivINij2K7YsC4g2LPZhNmK2YXYp9mG2Iwg2KXYqtmB2KfZgtmK", - "2Kkg2KjZitmGINmF2KcsINmK2LDZg9ixINin2YTYrdiv2YjYryDYo9mKINio2LnYrywg2YXYudin", - "2YXZhNipINio2YjZhNmG2K/Yp9iMINin2YTYpdi32YTYp9mCINi52YQg2KXZitmILg==", - "15HWsNa816jWtdeQ16nWtNeB15nXqiwg15HWuNa816jWuNeQINeQ1rHXnNa515TWtNeZ150sINeQ", - "1rXXqiDXlNa316nWuNa814HXnta315nWtNedLCDXldaw15DWtdeqINeU1rjXkNa416jWttel", - "15TWuNeZ1rDXqta415R0ZXN02KfZhNi12YHYrdin2Kog2KfZhNiq2ZHYrdmI2YQ=", - "77e9", - "77e6", - "2YXZj9mG2Y7Yp9mC2Y7YtNmO2KnZjyDYs9mP2KjZj9mE2ZAg2KfZkNiz2ZLYqtmQ2K7Zktiv2Y7Y", - "p9mF2ZAg2KfZhNmE2ZHZj9i62Y7YqdmQINmB2ZDZiiDYp9mE2YbZkdmP2LjZj9mF2ZAg2KfZhNmS", - "2YLZjtin2KbZkNmF2Y7YqdmQINmI2Y7ZgdmQ2YrZhSDZitmO2K7Zj9i12ZHZjiDYp9mE2KrZkdmO", - "2LfZktio2ZDZitmC2Y7Yp9iq2Y8g2KfZhNmS2K3Yp9iz2Y/ZiNio2ZDZitmR2Y7YqdmP2Iw=", - "4Zqb4ZqE4ZqT4ZqQ4ZqL4ZqS4ZqE4ZqA4ZqR4ZqE4ZqC4ZqR4ZqP4ZqF4Zqc", - "4Zqb4ZqA4ZqA4ZqA4ZqA4ZqA4ZqA4ZqA4ZqA4ZqA4ZqA4ZqA4ZqA4ZqA4ZqA4ZqA4ZqA4ZqA4ZqcCg==", - "4oCq4oCqdGVzdOKAqg==", - "4oCrdGVzdOKAqw==", - "4oCpdGVzdOKAqQ==", - "dGVzdOKBoHRlc3TigKs=", - "4oGmdGVzdOKBpw==", - "4bmwzLrMusyVb82eIMy3acyyzKzNh8yqzZluzJ3Ml82VdsyfzJzMmMymzZ9vzLbMmcywzKBrw6jN", - "msyuzLrMqsy5zLHMpCDMlnTMnc2VzLPMo8y7zKrNnmjMvM2TzLLMpsyzzJjMsmXNh8yjzLDMpsys", - "zY4gzKLMvMy7zLHMmGjNms2OzZnMnMyjzLLNhWnMpsyyzKPMsMykdsy7zY1lzLrMrcyzzKrMsC1t", - "zKJpzYVuzJbMusyezLLMr8ywZMy1zLzMn82ZzKnMvMyYzLMgzJ7MpcyxzLPMrXLMm8yXzJhlzZlw", - "zaByzLzMnsy7zK3Ml2XMusygzKPNn3PMmM2HzLPNjcydzYllzYnMpcyvzJ7Mss2azKzNnMe5zKzN", - "js2OzJ/Mls2HzKR0zY3MrMykzZPMvMytzZjNhWnMqsyxbs2gZ8y0zYkgzY/Nic2FY8yszJ9ozaFh", - "zKvMu8yvzZhvzKvMn8yWzY3MmcydzYlzzJfMpsyyLsyozLnNiMyj", - "zKHNk8yezYVJzJfMmMymzZ1uzYfNh82ZdsyuzKtva8yyzKvMmc2IacyWzZnMrcy5zKDMnm7Mocy7", - "zK7Mo8y6Z8yyzYjNmcytzZnMrM2OIMywdM2UzKZozJ7MsmXMosykIM2NzKzMss2WZsy0zJjNlcyj", - "w6jNluG6ucylzKlszZbNlM2aac2TzZrMps2gbs2WzY3Ml82TzLPMrmfNjSDMqG/NmsyqzaFmzJjM", - "o8ysIMyWzJjNlsyfzZnMrmPSic2UzKvNls2TzYfNls2FaMy1zKTMo82azZTDocyXzLzNlc2Fb8y8", - "zKPMpXPMsc2IzLrMlsymzLvNoi7Mm8yWzJ7MoMyrzLA=", - "zJfMus2WzLnMr82T4bmuzKTNjcylzYfNiGjMssyBZc2PzZPMvMyXzJnMvMyjzZQgzYfMnMyxzKDN", - "k82NzYVOzZXNoGXMl8yxesyYzJ3MnMy6zZlwzKTMusy5zY3Mr82aZcygzLvMoM2ccsyozKTNjcy6", - "zJbNlMyWzJZkzKDMn8ytzKzMnc2facymzZbMqc2TzZTMpGHMoMyXzKzNicyZbs2azZwgzLvMnsyw", - "zZrNhWjMtc2JacyzzJ52zKLNh+G4mc2OzZ8t0onMrcypzLzNlG3MpMytzKtpzZXNh8ydzKZuzJfN", - "meG4jcyfIMyvzLLNlc2ex6vMn8yvzLDMss2ZzLvMnWYgzKrMsMywzJfMlsytzJjNmGPMps2NzLLM", - "ns2NzKnMmeG4pc2aYcyuzY7Mn8yZzZzGocypzLnNjnPMpC7MncydINKJWsyhzJbMnM2WzLDMo82J", - "zJxhzZbMsM2ZzKzNoWzMssyrzLPNjcypZ8yhzJ/MvMyxzZrMnsyszYVvzJfNnC7Mnw==", - "zKZIzKzMpMyXzKTNnWXNnCDMnMylzJ3Mu82NzJ/MgXfMlWjMlsyvzZNvzJ3NmcyWzY7MscyuINKJ", - "zLrMmcyezJ/NiFfMt8y8zK1hzLrMqs2NxK/NiM2VzK3NmcyvzJx0zLbMvMyuc8yYzZnNlsyVIMyg", - "zKvMoELMu82NzZnNicyzzYVlzLVozLXMrM2HzKvNmWnMuc2TzLPMs8yuzY7Mq8yVbs2fZMy0zKrM", - "nMyWIMywzYnMqc2HzZnMss2ezYVUzZbMvM2TzKrNomjNj82TzK7Mu2XMrMydzJ/NhSDMpMy5zJ1X", - "zZnMnsydzZTNh82dzYVhzY/Nk82UzLnMvMyjbMy0zZTMsMykzJ/NlOG4vcyrLs2V", - "WsyuzJ7MoM2ZzZTNheG4gMyXzJ7NiMy7zJfhuLbNmc2OzK/MucyezZNHzLtPzK3Ml8yu", - "y5nJkG5i4bSJbMmQIMmQdcaDyZDJryDHncm5b2xvcCDKh8edIMedyblvccmQbCDKh24gyod1bnDh", - "tIlw4bSJyZR14bSJIMm5b2TJr8edyocgcG/Jr3Nu4bSJx50gb3AgcMedcyAnyofhtIlsx50gxoN1", - "4bSJyZRz4bSJZOG0iXDJkCDJuW7Kh8edyofJlMedc3VvyZQgJ8qHx53Jr8mQIMqH4bSJcyDJuW9s", - "b3Agya9uc2ThtIkgya/Hncm5b8ul", - "MDDLmcaWJC0=", - "77y0772I772FIO+9ke+9le+9ie+9g++9iyDvvYLvvZLvvY/vvZfvvY4g772G772P772YIO+9iu+9", - "le+9je+9kO+9kyDvvY/vvZbvvYXvvZIg772U772I772FIO+9jO+9ge+9mu+9mSDvvYTvvY/vvYc=", - "8J2Qk/CdkKHwnZCeIPCdkKrwnZCu8J2QovCdkJzwnZCkIPCdkJvwnZCr8J2QqPCdkLDwnZCnIPCd", - "kJ/wnZCo8J2QsSDwnZCj8J2QrvCdkKbwnZCp8J2QrCDwnZCo8J2Qr/CdkJ7wnZCrIPCdkK3wnZCh", - "8J2QniDwnZCl8J2QmvCdkLPwnZCyIPCdkJ3wnZCo8J2QoA==", - "8J2Vv/Cdlo3wnZaKIPCdlpbwnZaa8J2WjvCdlojwnZaQIPCdlofwnZaX8J2WlPCdlpzwnZaTIPCd", - "lovwnZaU8J2WnSDwnZaP8J2WmvCdlpLwnZaV8J2WmCDwnZaU8J2Wm/CdlorwnZaXIPCdlpnwnZaN", - "8J2WiiDwnZaR8J2WhvCdlp/wnZaeIPCdlonwnZaU8J2WjA==", - "8J2Ru/CdkonwnZKGIPCdkpLwnZKW8J2SivCdkoTwnZKMIPCdkoPwnZKT8J2SkPCdkpjwnZKPIPCd", - "kofwnZKQ8J2SmSDwnZKL8J2SlvCdko7wnZKR8J2SlCDwnZKQ8J2Sl/CdkobwnZKTIPCdkpXwnZKJ", - "8J2ShiDwnZKN8J2SgvCdkpvwnZKaIPCdkoXwnZKQ8J2SiA==", - "8J2To/Cdk7HwnZOuIPCdk7rwnZO+8J2TsvCdk6zwnZO0IPCdk6vwnZO78J2TuPCdlIDwnZO3IPCd", - "k6/wnZO48J2UgSDwnZOz8J2TvvCdk7bwnZO58J2TvCDwnZO48J2Tv/Cdk67wnZO7IPCdk73wnZOx", - "8J2TriDwnZO18J2TqvCdlIPwnZSCIPCdk63wnZO48J2TsA==", - "8J2Vi/CdlZnwnZWWIPCdlaLwnZWm8J2VmvCdlZTwnZWcIPCdlZPwnZWj8J2VoPCdlajwnZWfIPCd", - "lZfwnZWg8J2VqSDwnZWb8J2VpvCdlZ7wnZWh8J2VpCDwnZWg8J2Vp/CdlZbwnZWjIPCdlaXwnZWZ", - "8J2VliDwnZWd8J2VkvCdlavwnZWqIPCdlZXwnZWg8J2VmA==", - "8J2ag/CdmpHwnZqOIPCdmprwnZqe8J2akvCdmozwnZqUIPCdmovwnZqb8J2amPCdmqDwnZqXIPCd", - "mo/wnZqY8J2aoSDwnZqT8J2anvCdmpbwnZqZ8J2anCDwnZqY8J2an/Cdmo7wnZqbIPCdmp3wnZqR", - "8J2ajiDwnZqV8J2aivCdmqPwnZqiIPCdmo3wnZqY8J2akA==", - "4pKv4pKj4pKgIOKSrOKSsOKSpOKSnuKSpiDikp3ikq3ikqrikrLikqkg4pKh4pKq4pKzIOKSpeKS", - "sOKSqOKSq+KSriDikqrikrHikqDikq0g4pKv4pKj4pKgIOKSp+KSnOKSteKStCDikp/ikqrikqI=", - "PHNjcmlwdD5hbGVydCgxMjMpPC9zY3JpcHQ+", - "Jmx0O3NjcmlwdCZndDthbGVydCgmIzM5OzEyMyYjMzk7KTsmbHQ7L3NjcmlwdCZndDs=", - "PGltZyBzcmM9eCBvbmVycm9yPWFsZXJ0KDEyMykgLz4=", - "PHN2Zz48c2NyaXB0PjEyMzwxPmFsZXJ0KDEyMyk8L3NjcmlwdD4=", - "Ij48c2NyaXB0PmFsZXJ0KDEyMyk8L3NjcmlwdD4=", - "Jz48c2NyaXB0PmFsZXJ0KDEyMyk8L3NjcmlwdD4=", - "PjxzY3JpcHQ+YWxlcnQoMTIzKTwvc2NyaXB0Pg==", - "PC9zY3JpcHQ+PHNjcmlwdD5hbGVydCgxMjMpPC9zY3JpcHQ+", - "PCAvIHNjcmlwdCA+PCBzY3JpcHQgPmFsZXJ0KDEyMyk8IC8gc2NyaXB0ID4=", - "b25mb2N1cz1KYVZhU0NyaXB0OmFsZXJ0KDEyMykgYXV0b2ZvY3Vz", - "IiBvbmZvY3VzPUphVmFTQ3JpcHQ6YWxlcnQoMTIzKSBhdXRvZm9jdXM=", - "JyBvbmZvY3VzPUphVmFTQ3JpcHQ6YWxlcnQoMTIzKSBhdXRvZm9jdXM=", - "77ycc2NyaXB077yeYWxlcnQoMTIzKe+8nC9zY3JpcHTvvJ4=", - "PHNjPHNjcmlwdD5yaXB0PmFsZXJ0KDEyMyk8L3NjPC9zY3JpcHQ+cmlwdD4=", - "LS0+PHNjcmlwdD5hbGVydCgxMjMpPC9zY3JpcHQ+", - "IjthbGVydCgxMjMpO3Q9Ig==", - "JzthbGVydCgxMjMpO3Q9Jw==", - "SmF2YVNDcmlwdDphbGVydCgxMjMp", - "O2FsZXJ0KDEyMyk7", - "c3JjPUphVmFTQ3JpcHQ6cHJvbXB0KDEzMik=", - "Ij48c2NyaXB0PmFsZXJ0KDEyMyk7PC9zY3JpcHQgeD0i", - "Jz48c2NyaXB0PmFsZXJ0KDEyMyk7PC9zY3JpcHQgeD0n", - "PjxzY3JpcHQ+YWxlcnQoMTIzKTs8L3NjcmlwdCB4PQ==", - "IiBhdXRvZm9jdXMgb25rZXl1cD0iamF2YXNjcmlwdDphbGVydCgxMjMp", - "JyBhdXRvZm9jdXMgb25rZXl1cD0namF2YXNjcmlwdDphbGVydCgxMjMp", - "PHNjcmlwdHgyMHR5cGU9InRleHQvamF2YXNjcmlwdCI+amF2YXNjcmlwdDphbGVydCgxKTs8L3Nj", - "cmlwdD4=", - "PHNjcmlwdHgzRXR5cGU9InRleHQvamF2YXNjcmlwdCI+amF2YXNjcmlwdDphbGVydCgxKTs8L3Nj", - "cmlwdD4=", - "PHNjcmlwdHgwRHR5cGU9InRleHQvamF2YXNjcmlwdCI+amF2YXNjcmlwdDphbGVydCgxKTs8L3Nj", - "cmlwdD4=", - "PHNjcmlwdHgwOXR5cGU9InRleHQvamF2YXNjcmlwdCI+amF2YXNjcmlwdDphbGVydCgxKTs8L3Nj", - "cmlwdD4=", - "PHNjcmlwdHgwQ3R5cGU9InRleHQvamF2YXNjcmlwdCI+amF2YXNjcmlwdDphbGVydCgxKTs8L3Nj", - "cmlwdD4=", - "PHNjcmlwdHgyRnR5cGU9InRleHQvamF2YXNjcmlwdCI+amF2YXNjcmlwdDphbGVydCgxKTs8L3Nj", - "cmlwdD4=", - "PHNjcmlwdHgwQXR5cGU9InRleHQvamF2YXNjcmlwdCI+amF2YXNjcmlwdDphbGVydCgxKTs8L3Nj", - "cmlwdD4=", - "J2AiPjx4M0NzY3JpcHQ+amF2YXNjcmlwdDphbGVydCgxKTwvc2NyaXB0Pg==", - "J2AiPjx4MDBzY3JpcHQ+amF2YXNjcmlwdDphbGVydCgxKTwvc2NyaXB0Pg==", - "QUJDPGRpdiBzdHlsZT0ieHgzQWV4cHJlc3Npb24oamF2YXNjcmlwdDphbGVydCgxKSI+REVG", - "QUJDPGRpdiBzdHlsZT0ieDpleHByZXNzaW9ueDVDKGphdmFzY3JpcHQ6YWxlcnQoMSkiPkRFRg==", - "QUJDPGRpdiBzdHlsZT0ieDpleHByZXNzaW9ueDAwKGphdmFzY3JpcHQ6YWxlcnQoMSkiPkRFRg==", - "QUJDPGRpdiBzdHlsZT0ieDpleHB4MDByZXNzaW9uKGphdmFzY3JpcHQ6YWxlcnQoMSkiPkRFRg==", - "QUJDPGRpdiBzdHlsZT0ieDpleHB4NUNyZXNzaW9uKGphdmFzY3JpcHQ6YWxlcnQoMSkiPkRFRg==", - "QUJDPGRpdiBzdHlsZT0ieDp4MEFleHByZXNzaW9uKGphdmFzY3JpcHQ6YWxlcnQoMSkiPkRFRg==", - "QUJDPGRpdiBzdHlsZT0ieDp4MDlleHByZXNzaW9uKGphdmFzY3JpcHQ6YWxlcnQoMSkiPkRFRg==", - "QUJDPGRpdiBzdHlsZT0ieDp4RTN4ODB4ODBleHByZXNzaW9uKGphdmFzY3JpcHQ6YWxlcnQoMSki", - "PkRFRg==", - "QUJDPGRpdiBzdHlsZT0ieDp4RTJ4ODB4ODRleHByZXNzaW9uKGphdmFzY3JpcHQ6YWxlcnQoMSki", - "PkRFRg==", - "QUJDPGRpdiBzdHlsZT0ieDp4QzJ4QTBleHByZXNzaW9uKGphdmFzY3JpcHQ6YWxlcnQoMSkiPkRF", - "Rg==", - "QUJDPGRpdiBzdHlsZT0ieDp4RTJ4ODB4ODBleHByZXNzaW9uKGphdmFzY3JpcHQ6YWxlcnQoMSki", - "PkRFRg==", - "QUJDPGRpdiBzdHlsZT0ieDp4RTJ4ODB4OEFleHByZXNzaW9uKGphdmFzY3JpcHQ6YWxlcnQoMSki", - "PkRFRg==", - "QUJDPGRpdiBzdHlsZT0ieDp4MERleHByZXNzaW9uKGphdmFzY3JpcHQ6YWxlcnQoMSkiPkRFRg==", - "QUJDPGRpdiBzdHlsZT0ieDp4MENleHByZXNzaW9uKGphdmFzY3JpcHQ6YWxlcnQoMSkiPkRFRg==", - "QUJDPGRpdiBzdHlsZT0ieDp4RTJ4ODB4ODdleHByZXNzaW9uKGphdmFzY3JpcHQ6YWxlcnQoMSki", - "PkRFRg==", - "QUJDPGRpdiBzdHlsZT0ieDp4RUZ4QkJ4QkZleHByZXNzaW9uKGphdmFzY3JpcHQ6YWxlcnQoMSki", - "PkRFRg==", - "QUJDPGRpdiBzdHlsZT0ieDp4MjBleHByZXNzaW9uKGphdmFzY3JpcHQ6YWxlcnQoMSkiPkRFRg==", - "QUJDPGRpdiBzdHlsZT0ieDp4RTJ4ODB4ODhleHByZXNzaW9uKGphdmFzY3JpcHQ6YWxlcnQoMSki", - "PkRFRg==", - "QUJDPGRpdiBzdHlsZT0ieDp4MDBleHByZXNzaW9uKGphdmFzY3JpcHQ6YWxlcnQoMSkiPkRFRg==", - "QUJDPGRpdiBzdHlsZT0ieDp4RTJ4ODB4OEJleHByZXNzaW9uKGphdmFzY3JpcHQ6YWxlcnQoMSki", - "PkRFRg==", - "QUJDPGRpdiBzdHlsZT0ieDp4RTJ4ODB4ODZleHByZXNzaW9uKGphdmFzY3JpcHQ6YWxlcnQoMSki", - "PkRFRg==", - "QUJDPGRpdiBzdHlsZT0ieDp4RTJ4ODB4ODVleHByZXNzaW9uKGphdmFzY3JpcHQ6YWxlcnQoMSki", - "PkRFRg==", - "QUJDPGRpdiBzdHlsZT0ieDp4RTJ4ODB4ODJleHByZXNzaW9uKGphdmFzY3JpcHQ6YWxlcnQoMSki", - "PkRFRg==", - "QUJDPGRpdiBzdHlsZT0ieDp4MEJleHByZXNzaW9uKGphdmFzY3JpcHQ6YWxlcnQoMSkiPkRFRg==", - "QUJDPGRpdiBzdHlsZT0ieDp4RTJ4ODB4ODFleHByZXNzaW9uKGphdmFzY3JpcHQ6YWxlcnQoMSki", - "PkRFRg==", - "QUJDPGRpdiBzdHlsZT0ieDp4RTJ4ODB4ODNleHByZXNzaW9uKGphdmFzY3JpcHQ6YWxlcnQoMSki", - "PkRFRg==", - "QUJDPGRpdiBzdHlsZT0ieDp4RTJ4ODB4ODlleHByZXNzaW9uKGphdmFzY3JpcHQ6YWxlcnQoMSki", - "PkRFRg==", - "PGEgaHJlZj0ieDBCamF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6emVsZW1l", - "bnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieDBGamF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6emVsZW1l", - "bnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieEMyeEEwamF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6emVs", - "ZW1lbnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieDA1amF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6emVsZW1l", - "bnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieEUxeEEweDhFamF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6", - "emVsZW1lbnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieDE4amF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6emVsZW1l", - "bnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieDExamF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6emVsZW1l", - "bnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieEUyeDgweDg4amF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6", - "emVsZW1lbnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieEUyeDgweDg5amF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6", - "emVsZW1lbnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieEUyeDgweDgwamF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6", - "emVsZW1lbnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieDE3amF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6emVsZW1l", - "bnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieDAzamF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6emVsZW1l", - "bnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieDBFamF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6emVsZW1l", - "bnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieDFBamF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6emVsZW1l", - "bnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieDAwamF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6emVsZW1l", - "bnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieDEwamF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6emVsZW1l", - "bnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieEUyeDgweDgyamF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6", - "emVsZW1lbnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieDIwamF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6emVsZW1l", - "bnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieDEzamF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6emVsZW1l", - "bnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieDA5amF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6emVsZW1l", - "bnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieEUyeDgweDhBamF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6", - "emVsZW1lbnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieDE0amF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6emVsZW1l", - "bnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieDE5amF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6emVsZW1l", - "bnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieEUyeDgweEFGamF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6", - "emVsZW1lbnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieDFGamF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6emVsZW1l", - "bnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieEUyeDgweDgxamF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6", - "emVsZW1lbnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieDFEamF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6emVsZW1l", - "bnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieEUyeDgweDg3amF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6", - "emVsZW1lbnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieDA3amF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6emVsZW1l", - "bnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieEUxeDlBeDgwamF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6", - "emVsZW1lbnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieEUyeDgweDgzamF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6", - "emVsZW1lbnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieDA0amF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6emVsZW1l", - "bnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieDAxamF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6emVsZW1l", - "bnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieDA4amF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6emVsZW1l", - "bnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieEUyeDgweDg0amF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6", - "emVsZW1lbnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieEUyeDgweDg2amF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6", - "emVsZW1lbnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieEUzeDgweDgwamF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6", - "emVsZW1lbnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieDEyamF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6emVsZW1l", - "bnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieDBEamF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6emVsZW1l", - "bnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieDBBamF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6emVsZW1l", - "bnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieDBDamF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6emVsZW1l", - "bnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieDE1amF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6emVsZW1l", - "bnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieEUyeDgweEE4amF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6", - "emVsZW1lbnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieDE2amF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6emVsZW1l", - "bnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieDAyamF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6emVsZW1l", - "bnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieDFCamF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6emVsZW1l", - "bnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieDA2amF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6emVsZW1l", - "bnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieEUyeDgweEE5amF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6", - "emVsZW1lbnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieEUyeDgweDg1amF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6", - "emVsZW1lbnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieDFFamF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6emVsZW1l", - "bnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieEUyeDgxeDlGamF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6", - "emVsZW1lbnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0ieDFDamF2YXNjcmlwdDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6emVsZW1l", - "bnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0iamF2YXNjcmlwdHgwMDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6emVsZW1l", - "bnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0iamF2YXNjcmlwdHgzQTpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6emVsZW1l", - "bnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0iamF2YXNjcmlwdHgwOTpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6emVsZW1l", - "bnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0iamF2YXNjcmlwdHgwRDpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6emVsZW1l", - "bnQxIj50ZXN0PC9hPg==", - "PGEgaHJlZj0iamF2YXNjcmlwdHgwQTpqYXZhc2NyaXB0OmFsZXJ0KDEpIiBpZD0iZnV6emVsZW1l", - "bnQxIj50ZXN0PC9hPg==", - "YCInPjxpbWcgc3JjPXh4eDp4IHgwQW9uZXJyb3I9amF2YXNjcmlwdDphbGVydCgxKT4=", - "YCInPjxpbWcgc3JjPXh4eDp4IHgyMm9uZXJyb3I9amF2YXNjcmlwdDphbGVydCgxKT4=", - "YCInPjxpbWcgc3JjPXh4eDp4IHgwQm9uZXJyb3I9amF2YXNjcmlwdDphbGVydCgxKT4=", - "YCInPjxpbWcgc3JjPXh4eDp4IHgwRG9uZXJyb3I9amF2YXNjcmlwdDphbGVydCgxKT4=", - "YCInPjxpbWcgc3JjPXh4eDp4IHgyRm9uZXJyb3I9amF2YXNjcmlwdDphbGVydCgxKT4=", - "YCInPjxpbWcgc3JjPXh4eDp4IHgwOW9uZXJyb3I9amF2YXNjcmlwdDphbGVydCgxKT4=", - "YCInPjxpbWcgc3JjPXh4eDp4IHgwQ29uZXJyb3I9amF2YXNjcmlwdDphbGVydCgxKT4=", - "YCInPjxpbWcgc3JjPXh4eDp4IHgwMG9uZXJyb3I9amF2YXNjcmlwdDphbGVydCgxKT4=", - "YCInPjxpbWcgc3JjPXh4eDp4IHgyN29uZXJyb3I9amF2YXNjcmlwdDphbGVydCgxKT4=", - "YCInPjxpbWcgc3JjPXh4eDp4IHgyMG9uZXJyb3I9amF2YXNjcmlwdDphbGVydCgxKT4=", - "ImAnPjxzY3JpcHQ+eDNCamF2YXNjcmlwdDphbGVydCgxKTwvc2NyaXB0Pg==", - "ImAnPjxzY3JpcHQ+eDBEamF2YXNjcmlwdDphbGVydCgxKTwvc2NyaXB0Pg==", - "ImAnPjxzY3JpcHQ+eEVGeEJCeEJGamF2YXNjcmlwdDphbGVydCgxKTwvc2NyaXB0Pg==", - "ImAnPjxzY3JpcHQ+eEUyeDgweDgxamF2YXNjcmlwdDphbGVydCgxKTwvc2NyaXB0Pg==", - "ImAnPjxzY3JpcHQ+eEUyeDgweDg0amF2YXNjcmlwdDphbGVydCgxKTwvc2NyaXB0Pg==", - "ImAnPjxzY3JpcHQ+eEUzeDgweDgwamF2YXNjcmlwdDphbGVydCgxKTwvc2NyaXB0Pg==", - "ImAnPjxzY3JpcHQ+eDA5amF2YXNjcmlwdDphbGVydCgxKTwvc2NyaXB0Pg==", - "ImAnPjxzY3JpcHQ+eEUyeDgweDg5amF2YXNjcmlwdDphbGVydCgxKTwvc2NyaXB0Pg==", - "ImAnPjxzY3JpcHQ+eEUyeDgweDg1amF2YXNjcmlwdDphbGVydCgxKTwvc2NyaXB0Pg==", - "ImAnPjxzY3JpcHQ+eEUyeDgweDg4amF2YXNjcmlwdDphbGVydCgxKTwvc2NyaXB0Pg==", - "ImAnPjxzY3JpcHQ+eDAwamF2YXNjcmlwdDphbGVydCgxKTwvc2NyaXB0Pg==", - "ImAnPjxzY3JpcHQ+eEUyeDgweEE4amF2YXNjcmlwdDphbGVydCgxKTwvc2NyaXB0Pg==", - "ImAnPjxzY3JpcHQ+eEUyeDgweDhBamF2YXNjcmlwdDphbGVydCgxKTwvc2NyaXB0Pg==", - "ImAnPjxzY3JpcHQ+eEUxeDlBeDgwamF2YXNjcmlwdDphbGVydCgxKTwvc2NyaXB0Pg==", - "ImAnPjxzY3JpcHQ+eDBDamF2YXNjcmlwdDphbGVydCgxKTwvc2NyaXB0Pg==", - "ImAnPjxzY3JpcHQ+eDJCamF2YXNjcmlwdDphbGVydCgxKTwvc2NyaXB0Pg==", - "ImAnPjxzY3JpcHQ+eEYweDkweDk2eDlBamF2YXNjcmlwdDphbGVydCgxKTwvc2NyaXB0Pg==", - "ImAnPjxzY3JpcHQ+LWphdmFzY3JpcHQ6YWxlcnQoMSk8L3NjcmlwdD4=", - "ImAnPjxzY3JpcHQ+eDBBamF2YXNjcmlwdDphbGVydCgxKTwvc2NyaXB0Pg==", - "ImAnPjxzY3JpcHQ+eEUyeDgweEFGamF2YXNjcmlwdDphbGVydCgxKTwvc2NyaXB0Pg==", - "ImAnPjxzY3JpcHQ+eDdFamF2YXNjcmlwdDphbGVydCgxKTwvc2NyaXB0Pg==", - "ImAnPjxzY3JpcHQ+eEUyeDgweDg3amF2YXNjcmlwdDphbGVydCgxKTwvc2NyaXB0Pg==", - "ImAnPjxzY3JpcHQ+eEUyeDgxeDlGamF2YXNjcmlwdDphbGVydCgxKTwvc2NyaXB0Pg==", - "ImAnPjxzY3JpcHQ+eEUyeDgweEE5amF2YXNjcmlwdDphbGVydCgxKTwvc2NyaXB0Pg==", - "ImAnPjxzY3JpcHQ+eEMyeDg1amF2YXNjcmlwdDphbGVydCgxKTwvc2NyaXB0Pg==", - "ImAnPjxzY3JpcHQ+eEVGeEJGeEFFamF2YXNjcmlwdDphbGVydCgxKTwvc2NyaXB0Pg==", - "ImAnPjxzY3JpcHQ+eEUyeDgweDgzamF2YXNjcmlwdDphbGVydCgxKTwvc2NyaXB0Pg==", - "ImAnPjxzY3JpcHQ+eEUyeDgweDhCamF2YXNjcmlwdDphbGVydCgxKTwvc2NyaXB0Pg==", - "ImAnPjxzY3JpcHQ+eEVGeEJGeEJFamF2YXNjcmlwdDphbGVydCgxKTwvc2NyaXB0Pg==", - "ImAnPjxzY3JpcHQ+eEUyeDgweDgwamF2YXNjcmlwdDphbGVydCgxKTwvc2NyaXB0Pg==", - "ImAnPjxzY3JpcHQ+eDIxamF2YXNjcmlwdDphbGVydCgxKTwvc2NyaXB0Pg==", - "ImAnPjxzY3JpcHQ+eEUyeDgweDgyamF2YXNjcmlwdDphbGVydCgxKTwvc2NyaXB0Pg==", - "ImAnPjxzY3JpcHQ+eEUyeDgweDg2amF2YXNjcmlwdDphbGVydCgxKTwvc2NyaXB0Pg==", - "ImAnPjxzY3JpcHQ+eEUxeEEweDhFamF2YXNjcmlwdDphbGVydCgxKTwvc2NyaXB0Pg==", - "ImAnPjxzY3JpcHQ+eDBCamF2YXNjcmlwdDphbGVydCgxKTwvc2NyaXB0Pg==", - "ImAnPjxzY3JpcHQ+eDIwamF2YXNjcmlwdDphbGVydCgxKTwvc2NyaXB0Pg==", - "ImAnPjxzY3JpcHQ+eEMyeEEwamF2YXNjcmlwdDphbGVydCgxKTwvc2NyaXB0Pg==", - "PGltZyB4MDBzcmM9eCBvbmVycm9yPSJhbGVydCgxKSI+", - "PGltZyB4NDdzcmM9eCBvbmVycm9yPSJqYXZhc2NyaXB0OmFsZXJ0KDEpIj4=", - "PGltZyB4MTFzcmM9eCBvbmVycm9yPSJqYXZhc2NyaXB0OmFsZXJ0KDEpIj4=", - "PGltZyB4MTJzcmM9eCBvbmVycm9yPSJqYXZhc2NyaXB0OmFsZXJ0KDEpIj4=", - "PGltZ3g0N3NyYz14IG9uZXJyb3I9ImphdmFzY3JpcHQ6YWxlcnQoMSkiPg==", - "PGltZ3gxMHNyYz14IG9uZXJyb3I9ImphdmFzY3JpcHQ6YWxlcnQoMSkiPg==", - "PGltZ3gxM3NyYz14IG9uZXJyb3I9ImphdmFzY3JpcHQ6YWxlcnQoMSkiPg==", - "PGltZ3gzMnNyYz14IG9uZXJyb3I9ImphdmFzY3JpcHQ6YWxlcnQoMSkiPg==", - "PGltZ3g0N3NyYz14IG9uZXJyb3I9ImphdmFzY3JpcHQ6YWxlcnQoMSkiPg==", - "PGltZ3gxMXNyYz14IG9uZXJyb3I9ImphdmFzY3JpcHQ6YWxlcnQoMSkiPg==", - "PGltZyB4NDdzcmM9eCBvbmVycm9yPSJqYXZhc2NyaXB0OmFsZXJ0KDEpIj4=", - "PGltZyB4MzRzcmM9eCBvbmVycm9yPSJqYXZhc2NyaXB0OmFsZXJ0KDEpIj4=", - "PGltZyB4MzlzcmM9eCBvbmVycm9yPSJqYXZhc2NyaXB0OmFsZXJ0KDEpIj4=", - "PGltZyB4MDBzcmM9eCBvbmVycm9yPSJqYXZhc2NyaXB0OmFsZXJ0KDEpIj4=", - "PGltZyBzcmN4MDk9eCBvbmVycm9yPSJqYXZhc2NyaXB0OmFsZXJ0KDEpIj4=", - "PGltZyBzcmN4MTA9eCBvbmVycm9yPSJqYXZhc2NyaXB0OmFsZXJ0KDEpIj4=", - "PGltZyBzcmN4MTM9eCBvbmVycm9yPSJqYXZhc2NyaXB0OmFsZXJ0KDEpIj4=", - "PGltZyBzcmN4MzI9eCBvbmVycm9yPSJqYXZhc2NyaXB0OmFsZXJ0KDEpIj4=", - "PGltZyBzcmN4MTI9eCBvbmVycm9yPSJqYXZhc2NyaXB0OmFsZXJ0KDEpIj4=", - "PGltZyBzcmN4MTE9eCBvbmVycm9yPSJqYXZhc2NyaXB0OmFsZXJ0KDEpIj4=", - "PGltZyBzcmN4MDA9eCBvbmVycm9yPSJqYXZhc2NyaXB0OmFsZXJ0KDEpIj4=", - "PGltZyBzcmN4NDc9eCBvbmVycm9yPSJqYXZhc2NyaXB0OmFsZXJ0KDEpIj4=", - "PGltZyBzcmM9eHgwOW9uZXJyb3I9ImphdmFzY3JpcHQ6YWxlcnQoMSkiPg==", - "PGltZyBzcmM9eHgxMG9uZXJyb3I9ImphdmFzY3JpcHQ6YWxlcnQoMSkiPg==", - "PGltZyBzcmM9eHgxMW9uZXJyb3I9ImphdmFzY3JpcHQ6YWxlcnQoMSkiPg==", - "PGltZyBzcmM9eHgxMm9uZXJyb3I9ImphdmFzY3JpcHQ6YWxlcnQoMSkiPg==", - "PGltZyBzcmM9eHgxM29uZXJyb3I9ImphdmFzY3JpcHQ6YWxlcnQoMSkiPg==", - "PGltZ1thXVtiXVtjXXNyY1tkXT14W2Vdb25lcnJvcj1bZl0iYWxlcnQoMSkiPg==", - "PGltZyBzcmM9eCBvbmVycm9yPXgwOSJqYXZhc2NyaXB0OmFsZXJ0KDEpIj4=", - "PGltZyBzcmM9eCBvbmVycm9yPXgxMCJqYXZhc2NyaXB0OmFsZXJ0KDEpIj4=", - "PGltZyBzcmM9eCBvbmVycm9yPXgxMSJqYXZhc2NyaXB0OmFsZXJ0KDEpIj4=", - "PGltZyBzcmM9eCBvbmVycm9yPXgxMiJqYXZhc2NyaXB0OmFsZXJ0KDEpIj4=", - "PGltZyBzcmM9eCBvbmVycm9yPXgzMiJqYXZhc2NyaXB0OmFsZXJ0KDEpIj4=", - "PGltZyBzcmM9eCBvbmVycm9yPXgwMCJqYXZhc2NyaXB0OmFsZXJ0KDEpIj4=", - "PGEgaHJlZj1qYXZhJiMxJiMyJiMzJiM0JiM1JiM2JiM3JiM4JiMxMSYjMTJzY3JpcHQ6amF2YXNj", - "cmlwdDphbGVydCgxKT5YWFg8L2E+", - "PGltZyBzcmM9InhgIGA8c2NyaXB0PmphdmFzY3JpcHQ6YWxlcnQoMSk8L3NjcmlwdD4iYCBgPg==", - "PGltZyBzcmMgb25lcnJvciAvIiAnIj0gYWx0PWphdmFzY3JpcHQ6YWxlcnQoMSkvLyI+", - "PHRpdGxlIG9ucHJvcGVydHljaGFuZ2U9amF2YXNjcmlwdDphbGVydCgxKT48L3RpdGxlPjx0aXRs", - "ZSB0aXRsZT0+", - "PGEgaHJlZj1odHRwOi8vZm9vLmJhci8jeD1geT48L2E+PGltZyBhbHQ9ImA+PGltZyBzcmM9eDp4", - "IG9uZXJyb3I9amF2YXNjcmlwdDphbGVydCgxKT48L2E+Ij4=", - "PCEtLVtpZl0+PHNjcmlwdD5qYXZhc2NyaXB0OmFsZXJ0KDEpPC9zY3JpcHQgLS0+", - "PCEtLVtpZjxpbWcgc3JjPXggb25lcnJvcj1qYXZhc2NyaXB0OmFsZXJ0KDEpLy9dPiAtLT4=", - "PHNjcmlwdCBzcmM9Ii8lKGpzY3JpcHQpcyI+PC9zY3JpcHQ+", - "PHNjcmlwdCBzcmM9IlwlKGpzY3JpcHQpcyI+PC9zY3JpcHQ+", - "PElNRyAiIiI+PFNDUklQVD5hbGVydCgiWFNTIik8L1NDUklQVD4iPg==", - "PElNRyBTUkM9amF2YXNjcmlwdDphbGVydChTdHJpbmcuZnJvbUNoYXJDb2RlKDg4LDgzLDgzKSk+", - "PElNRyBTUkM9IyBvbm1vdXNlb3Zlcj0iYWxlcnQoJ3h4cycpIj4=", - "PElNRyBTUkM9IG9ubW91c2VvdmVyPSJhbGVydCgneHhzJykiPg==", - "PElNRyBvbm1vdXNlb3Zlcj0iYWxlcnQoJ3h4cycpIj4=", - "PElNRyBTUkM9JiMxMDY7JiM5NzsmIzExODsmIzk3OyYjMTE1OyYjOTk7JiMxMTQ7JiMxMDU7JiMx", - "MTI7JiMxMTY7JiM1ODsmIzk3OyYjMTA4OyYjMTAxOyYjMTE0OyYjMTE2OyYjNDA7JiMzOTsmIzg4", - "OyYjODM7JiM4MzsmIzM5OyYjNDE7Pg==", - "PElNRyBTUkM9JiMwMDAwMTA2JiMwMDAwMDk3JiMwMDAwMTE4JiMwMDAwMDk3JiMwMDAwMTE1JiMw", - "MDAwMDk5JiMwMDAwMTE0JiMwMDAwMTA1JiMwMDAwMTEyJiMwMDAwMTE2JiMwMDAwMDU4JiMwMDAw", - "MDk3JiMwMDAwMTA4JiMwMDAwMTAxJiMwMDAwMTE0JiMwMDAwMTE2JiMwMDAwMDQwJiMwMDAwMDM5", - "JiMwMDAwMDg4JiMwMDAwMDgzJiMwMDAwMDgzJiMwMDAwMDM5JiMwMDAwMDQxPg==", - "PElNRyBTUkM9JiN4NkEmI3g2MSYjeDc2JiN4NjEmI3g3MyYjeDYzJiN4NzImI3g2OSYjeDcwJiN4", - "NzQmI3gzQSYjeDYxJiN4NkMmI3g2NSYjeDcyJiN4NzQmI3gyOCYjeDI3JiN4NTgmI3g1MyYjeDUz", - "JiN4MjcmI3gyOT4=", - "PElNRyBTUkM9ImphdiBhc2NyaXB0OmFsZXJ0KCdYU1MnKTsiPg==", - "PElNRyBTUkM9ImphdiYjeDA5O2FzY3JpcHQ6YWxlcnQoJ1hTUycpOyI+", - "PElNRyBTUkM9ImphdiYjeDBBO2FzY3JpcHQ6YWxlcnQoJ1hTUycpOyI+", - "PElNRyBTUkM9ImphdiYjeDBEO2FzY3JpcHQ6YWxlcnQoJ1hTUycpOyI+", - "cGVybCAtZSAncHJpbnQgIjxJTUcgU1JDPWphdmEwc2NyaXB0OmFsZXJ0KCJYU1MiKT4iOycgPiBv", - "dXQ=", - "PElNRyBTUkM9IiAmIzE0OyBqYXZhc2NyaXB0OmFsZXJ0KCdYU1MnKTsiPg==", - "PFNDUklQVC9YU1MgU1JDPSJodHRwOi8vaGEuY2tlcnMub3JnL3hzcy5qcyI+PC9TQ1JJUFQ+", - "PEJPRFkgb25sb2FkISMkJSYoKSp+Ky1fLiw6Oz9AWy98XV5gPWFsZXJ0KCJYU1MiKT4=", - "PFNDUklQVC9TUkM9Imh0dHA6Ly9oYS5ja2Vycy5vcmcveHNzLmpzIj48L1NDUklQVD4=", - "PDxTQ1JJUFQ+YWxlcnQoIlhTUyIpOy8vPDwvU0NSSVBUPg==", - "PFNDUklQVCBTUkM9aHR0cDovL2hhLmNrZXJzLm9yZy94c3MuanM/PCBCID4=", - "PFNDUklQVCBTUkM9Ly9oYS5ja2Vycy5vcmcvLmo+", - "PElNRyBTUkM9ImphdmFzY3JpcHQ6YWxlcnQoJ1hTUycpIg==", - "PGlmcmFtZSBzcmM9aHR0cDovL2hhLmNrZXJzLm9yZy9zY3JpcHRsZXQuaHRtbCA8", - "IjthbGVydCgnWFNTJyk7Ly8=", - "PHUgb25jb3B5PWFsZXJ0KCk+IENvcHkgbWU8L3U+", - "PGkgb253aGVlbD1hbGVydCgxKT4gU2Nyb2xsIG92ZXIgbWUgPC9pPg==", - "PHBsYWludGV4dD4=", - "aHR0cDovL2EvJSUzMCUzMA==", - "PC90ZXh0YXJlYT48c2NyaXB0PmFsZXJ0KDEyMyk8L3NjcmlwdD4=", - "MTtEUk9QIFRBQkxFIHVzZXJz", - "MSc7IERST1AgVEFCTEUgdXNlcnMtLSAx", - "JyBPUiAxPTEgLS0gMQ==", - "JyBPUiAnMSc9JzE=", - "JQ==", - "Xw==", - "LQ==", - "LS0=", - "LS12ZXJzaW9u", - "LS1oZWxw", - "JFVTRVI=", - "L2Rldi9udWxsOyB0b3VjaCAvdG1wL2JsbnMuZmFpbCA7IGVjaG8=", - "YHRvdWNoIC90bXAvYmxucy5mYWlsYA==", - "JCh0b3VjaCAvdG1wL2JsbnMuZmFpbCk=", - "QHtbc3lzdGVtICJ0b3VjaCAvdG1wL2JsbnMuZmFpbCJdfQ==", - "ZXZhbCgicHV0cyAnaGVsbG8gd29ybGQnIik=", - "U3lzdGVtKCJscyAtYWwgLyIp", - "YGxzIC1hbCAvYA==", - "S2VybmVsLmV4ZWMoImxzIC1hbCAvIik=", - "S2VybmVsLmV4aXQoMSk=", - "JXgoJ2xzIC1hbCAvJyk=", - "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iSVNPLTg4NTktMSI/PjwhRE9DVFlQRSBmb28g", - "WyA8IUVMRU1FTlQgZm9vIEFOWSA+PCFFTlRJVFkgeHhlIFNZU1RFTSAiZmlsZTovLy9ldGMvcGFz", - "c3dkIiA+XT48Zm9vPiZ4eGU7PC9mb28+", - "JEhPTUU=", - "JEVOVnsnSE9NRSd9", - "JWQ=", - "JXM=", - "ezB9", - "JSouKnM=", - "Li4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vZXRjL3Bhc3N3ZCUwMA==", - "Li4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vZXRjL2hvc3Rz", - "KCkgeyAwOyB9OyB0b3VjaCAvdG1wL2JsbnMuc2hlbGxzaG9jazEuZmFpbDs=", - "KCkgeyBfOyB9ID5fWyQoJCgpKV0geyB0b3VjaCAvdG1wL2JsbnMuc2hlbGxzaG9jazIuZmFpbDsg", - "fQ==", - "PDw8ICVzKHVuPSclcycpID0gJXU=", - "KysrQVRIMA==", - "Q09O", - "UFJO", - "QVVY", - "Q0xPQ0sk", - "TlVM", - "QTo=", - "Wlo6", - "Q09NMQ==", - "TFBUMQ==", - "TFBUMg==", - "TFBUMw==", - "Q09NMg==", - "Q09NMw==", - "Q09NNA==", - "RENDIFNFTkQgU1RBUlRLRVlMT0dHRVIgMCAwIDA=", - "U2N1bnRob3JwZSBHZW5lcmFsIEhvc3BpdGFs", - "UGVuaXN0b25lIENvbW11bml0eSBDaHVyY2g=", - "TGlnaHR3YXRlciBDb3VudHJ5IFBhcms=", - "SmltbXkgQ2xpdGhlcm9l", - "SG9ybmltYW4gTXVzZXVt", - "c2hpdGFrZSBtdXNocm9vbXM=", - "Um9tYW5zSW5TdXNzZXguY28udWs=", - "aHR0cDovL3d3dy5jdW0ucWMuY2Ev", - "Q3JhaWcgQ29ja2J1cm4sIFNvZnR3YXJlIFNwZWNpYWxpc3Q=", - "TGluZGEgQ2FsbGFoYW4=", - "RHIuIEhlcm1hbiBJLiBMaWJzaGl0eg==", - "bWFnbmEgY3VtIGxhdWRl", - "U3VwZXIgQm93bCBYWFg=", - "bWVkaWV2YWwgZXJlY3Rpb24gb2YgcGFyYXBldHM=", - "ZXZhbHVhdGU=", - "bW9jaGE=", - "ZXhwcmVzc2lvbg==", - "QXJzZW5hbCBjYW5hbA==", - "Y2xhc3NpYw==", - "VHlzb24gR2F5", - "RGljayBWYW4gRHlrZQ==", - "YmFzZW1lbnQ=", - "SWYgeW91J3JlIHJlYWRpbmcgdGhpcywgeW91J3ZlIGJlZW4gaW4gYSBjb21hIGZvciBhbG1vc3Qg", - "MjAgeWVhcnMgbm93LiBXZSdyZSB0cnlpbmcgYSBuZXcgdGVjaG5pcXVlLiBXZSBkb24ndCBrbm93", - "IHdoZXJlIHRoaXMgbWVzc2FnZSB3aWxsIGVuZCB1cCBpbiB5b3VyIGRyZWFtLCBidXQgd2UgaG9w", - "ZSBpdCB3b3Jrcy4gUGxlYXNlIHdha2UgdXAsIHdlIG1pc3MgeW91Lg==", - "Um9zZXMgYXJlIBtbMDszMW1yZWQbWzBtLCB2aW9sZXRzIGFyZSAbWzA7MzRtYmx1ZS4gSG9wZSB5", - "b3UgZW5qb3kgdGVybWluYWwgaHVl", - "QnV0IG5vdy4uLhtbMjBDZm9yIG15IGdyZWF0ZXN0IHRyaWNrLi4uG1s4bQ==", - "VGhlIHF1aWMICAgICAhrIGJyb3duIGZvBwcHBwcHBwcHBwd4Li4uIFtCZWVlZXBd", - "UG93ZXLZhNmP2YTZj9i12ZHYqNmP2YTZj9mE2LXZkdio2Y/Ysdix2Ysg4KWjIOClo2gg4KWjIOCl", - "o+WGlw==", - "2q/ahtm+2pg=", - "eyUgcHJpbnQgJ3gnICogNjQgKiAxMDI0KiozICV9", - "e3sgIiIuX19jbGFzc19fLl9fbXJvX19bMl0uX19zdWJjbGFzc2VzX18oKVs0MF0oIi9ldGMvcGFz", - "c3dkIikucmVhZCgpIH19" -] - diff --git a/compiler/noirc_frontend/src/debug/mod.rs b/compiler/noirc_frontend/src/debug/mod.rs index 71e0d44b478..c99cfdc4a5c 100644 --- a/compiler/noirc_frontend/src/debug/mod.rs +++ b/compiler/noirc_frontend/src/debug/mod.rs @@ -145,6 +145,7 @@ impl DebugInstrumenter { pattern: ast::Pattern::Identifier(ident("__debug_expr", ret_expr.span)), r#type: ast::UnresolvedType::unspecified(), expression: ret_expr.clone(), + attributes: vec![], }), span: ret_expr.span, }; @@ -248,6 +249,7 @@ impl DebugInstrumenter { }), span: let_stmt.expression.span, }, + attributes: vec![], }), span: *span, } @@ -273,6 +275,7 @@ impl DebugInstrumenter { pattern: ast::Pattern::Identifier(ident("__debug_expr", assign_stmt.expression.span)), r#type: ast::UnresolvedType::unspecified(), expression: assign_stmt.expression.clone(), + attributes: vec![], }); let expression_span = assign_stmt.expression.span; let new_assign_stmt = match &assign_stmt.lvalue { @@ -282,7 +285,7 @@ impl DebugInstrumenter { .unwrap_or_else(|| panic!("var lookup failed for var_name={}", &id.0.contents)); build_assign_var_stmt(var_id, id_expr(&ident("__debug_expr", id.span()))) } - ast::LValue::Dereference(_lv, span) => { + ast::LValue::Dereference(_lv) => { // TODO: this is a dummy statement for now, but we should // somehow track the derefence and update the pointed to // variable @@ -303,16 +306,16 @@ impl DebugInstrumenter { }); break; } - ast::LValue::MemberAccess { object, field_name, span } => { + ast::LValue::MemberAccess { object, field_name } => { cursor = object; let field_name_id = self.insert_field_name(&field_name.0.contents); - indexes.push(sint_expr(-(field_name_id.0 as i128), *span)); + indexes.push(sint_expr(-(field_name_id.0 as i128), expression_span)); } - ast::LValue::Index { index, array, span: _ } => { + ast::LValue::Index { index, array } => { cursor = array; indexes.push(index.clone()); } - ast::LValue::Dereference(_ref, _span) => { + ast::LValue::Dereference(_ref) => { unimplemented![] } } diff --git a/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs b/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs index fcb20c740c7..6fbb3b67546 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs @@ -102,8 +102,12 @@ impl<'a> ModCollector<'a> { for global in globals { let name = global.pattern.name_ident().clone(); - let global_id = - context.def_interner.push_empty_global(name.clone(), self.module_id, self.file_id); + let global_id = context.def_interner.push_empty_global( + name.clone(), + self.module_id, + self.file_id, + global.attributes.clone(), + ); // Add the statement to the scope so its path can be looked up later let result = self.def_collector.def_map.modules[self.module_id.0] @@ -455,6 +459,7 @@ impl<'a> ModCollector<'a> { name.clone(), trait_id.0.local_id, self.file_id, + vec![], ); if let Err((first_def, second_def)) = self.def_collector.def_map.modules diff --git a/compiler/noirc_frontend/src/hir/def_map/mod.rs b/compiler/noirc_frontend/src/hir/def_map/mod.rs index 157227f763e..7c0090ff95b 100644 --- a/compiler/noirc_frontend/src/hir/def_map/mod.rs +++ b/compiler/noirc_frontend/src/hir/def_map/mod.rs @@ -2,13 +2,13 @@ use crate::graph::CrateId; use crate::hir::def_collector::dc_crate::{CompilationError, DefCollector}; use crate::hir::Context; use crate::macros_api::MacroProcessor; -use crate::node_interner::{FuncId, NodeInterner, StructId}; +use crate::node_interner::{FuncId, GlobalId, NodeInterner, StructId}; use crate::parser::{parse_program, ParsedModule, ParserError}; use crate::token::{FunctionAttribute, SecondaryAttribute, TestScope}; use arena::{Arena, Index}; use fm::{FileId, FileManager}; use noirc_errors::Location; -use std::collections::BTreeMap; +use std::collections::{BTreeMap, HashMap}; mod module_def; pub use module_def::*; mod item_scope; @@ -217,20 +217,37 @@ impl CrateDefMap { }) .collect(); - let events = module - .type_definitions() - .filter_map(|id| { - id.as_type().filter(|struct_id| { - interner - .struct_attributes(struct_id) - .iter() - .any(|attr| attr == &SecondaryAttribute::Event) - }) - }) - .collect(); + let mut outputs = + ContractOutputs { structs: HashMap::new(), globals: HashMap::new() }; + + interner.get_all_globals().iter().for_each(|global_info| { + interner.global_attributes(&global_info.id).iter().for_each(|attr| { + if let SecondaryAttribute::Abi(tag) = attr { + if let Some(tagged) = outputs.globals.get_mut(tag) { + tagged.push(global_info.id); + } else { + outputs.globals.insert(tag.to_string(), vec![global_info.id]); + } + } + }); + }); + + module.type_definitions().for_each(|id| { + if let ModuleDefId::TypeId(struct_id) = id { + interner.struct_attributes(&struct_id).iter().for_each(|attr| { + if let SecondaryAttribute::Abi(tag) = attr { + if let Some(tagged) = outputs.structs.get_mut(tag) { + tagged.push(struct_id); + } else { + outputs.structs.insert(tag.to_string(), vec![struct_id]); + } + } + }); + } + }); let name = self.get_module_path(id, module.parent); - Some(Contract { name, location: module.location, functions, events }) + Some(Contract { name, location: module.location, functions, outputs }) } else { None } @@ -283,6 +300,11 @@ pub struct ContractFunctionMeta { pub is_entry_point: bool, } +pub struct ContractOutputs { + pub structs: HashMap>, + pub globals: HashMap>, +} + /// A 'contract' in Noir source code with a given name, functions and events. /// This is not an AST node, it is just a convenient form to return for CrateDefMap::get_all_contracts. pub struct Contract { @@ -290,7 +312,7 @@ pub struct Contract { pub name: String, pub location: Location, pub functions: Vec, - pub events: Vec, + pub outputs: ContractOutputs, } /// Given a FileId, fetch the File, from the FileManager and parse it's content diff --git a/compiler/noirc_frontend/src/hir/resolution/errors.rs b/compiler/noirc_frontend/src/hir/resolution/errors.rs index 3c6c0582292..b95d7d3351e 100644 --- a/compiler/noirc_frontend/src/hir/resolution/errors.rs +++ b/compiler/noirc_frontend/src/hir/resolution/errors.rs @@ -80,6 +80,8 @@ pub enum ResolverError { NestedSlices { span: Span }, #[error("#[recursive] attribute is only allowed on entry points to a program")] MisplacedRecursiveAttribute { ident: Ident }, + #[error("#[abi(tag)] attribute is only allowed in contracts")] + AbiAttributeOusideContract { span: Span }, #[error("Usage of the `#[foreign]` or `#[builtin]` function attributes are not allowed outside of the Noir standard library")] LowLevelFunctionOutsideOfStdlib { ident: Ident }, #[error("Dependency cycle found, '{item}' recursively depends on itself: {cycle} ")] @@ -314,6 +316,13 @@ impl From for Diagnostic { diag.add_note("The `#[recursive]` attribute specifies to the backend whether it should use a prover which generates proofs that are friendly for recursive verification in another circuit".to_owned()); diag } + ResolverError::AbiAttributeOusideContract { span } => { + Diagnostic::simple_error( + "#[abi(tag)] attributes can only be used in contracts".to_string(), + "misplaced #[abi(tag)] attribute".to_string(), + span, + ) + }, ResolverError::LowLevelFunctionOutsideOfStdlib { ident } => Diagnostic::simple_error( "Definition of low-level function outside of standard library".into(), "Usage of the `#[foreign]` or `#[builtin]` function attributes are not allowed outside of the Noir standard library".into(), diff --git a/compiler/noirc_frontend/src/hir/resolution/resolver.rs b/compiler/noirc_frontend/src/hir/resolution/resolver.rs index ec149dee96e..2e1b4b56da3 100644 --- a/compiler/noirc_frontend/src/hir/resolution/resolver.rs +++ b/compiler/noirc_frontend/src/hir/resolution/resolver.rs @@ -19,6 +19,7 @@ use crate::hir_def::expr::{ }; use crate::hir_def::traits::{Trait, TraitConstraint}; +use crate::macros_api::SecondaryAttribute; use crate::token::{Attributes, FunctionAttribute}; use regex::Regex; use std::collections::{BTreeMap, HashSet}; @@ -616,7 +617,17 @@ impl<'a> Resolver<'a> { match self.lookup_struct_or_error(path) { Some(struct_type) => { let expected_generic_count = struct_type.borrow().generics.len(); - + if !self.in_contract + && self + .interner + .struct_attributes(&struct_type.borrow().id) + .iter() + .any(|attr| matches!(attr, SecondaryAttribute::Abi(_))) + { + self.push_err(ResolverError::AbiAttributeOusideContract { + span: struct_type.borrow().name.span(), + }); + } self.verify_generics_count(expected_generic_count, &mut args, span, || { struct_type.borrow().to_string() }); @@ -1162,10 +1173,19 @@ impl<'a> Resolver<'a> { let global_id = self.interner.next_global_id(); let definition = DefinitionKind::Global(global_id); + if !self.in_contract + && let_stmt.attributes.iter().any(|attr| matches!(attr, SecondaryAttribute::Abi(_))) + { + self.push_err(ResolverError::AbiAttributeOusideContract { + span: let_stmt.pattern.span(), + }); + } + HirStatement::Let(HirLetStatement { pattern: self.resolve_pattern(let_stmt.pattern, definition), r#type: self.resolve_type(let_stmt.r#type), expression, + attributes: let_stmt.attributes, }) } @@ -1178,6 +1198,7 @@ impl<'a> Resolver<'a> { pattern: self.resolve_pattern(let_stmt.pattern, definition), r#type: self.resolve_type(let_stmt.r#type), expression, + attributes: let_stmt.attributes, }) } StatementKind::Constrain(constrain_stmt) => { @@ -1306,23 +1327,18 @@ impl<'a> Resolver<'a> { HirLValue::Ident(ident.0, Type::Error) } - LValue::MemberAccess { object, field_name, span } => HirLValue::MemberAccess { - object: Box::new(self.resolve_lvalue(*object)), - field_name, - location: Location::new(span, self.file), - field_index: None, - typ: Type::Error, - }, - LValue::Index { array, index, span } => { + LValue::MemberAccess { object, field_name } => { + let object = Box::new(self.resolve_lvalue(*object)); + HirLValue::MemberAccess { object, field_name, field_index: None, typ: Type::Error } + } + LValue::Index { array, index } => { let array = Box::new(self.resolve_lvalue(*array)); let index = self.resolve_expression(index); - let location = Location::new(span, self.file); - HirLValue::Index { array, index, location, typ: Type::Error } + HirLValue::Index { array, index, typ: Type::Error } } - LValue::Dereference(lvalue, span) => { + LValue::Dereference(lvalue) => { let lvalue = Box::new(self.resolve_lvalue(*lvalue)); - let location = Location::new(span, self.file); - HirLValue::Dereference { lvalue, location, element_type: Type::Error } + HirLValue::Dereference { lvalue, element_type: Type::Error } } } } diff --git a/compiler/noirc_frontend/src/hir/type_check/errors.rs b/compiler/noirc_frontend/src/hir/type_check/errors.rs index 6c28aabe0fb..c881efcfc45 100644 --- a/compiler/noirc_frontend/src/hir/type_check/errors.rs +++ b/compiler/noirc_frontend/src/hir/type_check/errors.rs @@ -65,6 +65,8 @@ pub enum TypeCheckError { VariableMustBeMutable { name: String, span: Span }, #[error("No method named '{method_name}' found for type '{object_type}'")] UnresolvedMethodCall { method_name: String, object_type: Type, span: Span }, + #[error("Comparisons are invalid on Field types. Try casting the operands to a sized integer type first")] + InvalidComparisonOnField { span: Span }, #[error("Integers must have the same signedness LHS is {sign_x:?}, RHS is {sign_y:?}")] IntegerSignedness { sign_x: Signedness, sign_y: Signedness, span: Span }, #[error("Integers must have the same bit width LHS is {bit_width_x}, RHS is {bit_width_y}")] @@ -74,7 +76,7 @@ pub enum TypeCheckError { #[error("{kind} cannot be used in a unary operation")] InvalidUnaryOp { kind: String, span: Span }, #[error("Bitwise operations are invalid on Field types. Try casting the operands to a sized integer type first.")] - FieldBitwiseOp { span: Span }, + InvalidBitwiseOperationOnField { span: Span }, #[error("Integer cannot be used with type {typ}")] IntegerTypeMismatch { typ: Type, span: Span }, #[error("Cannot use an integer and a Field in a binary operation, try converting the Field into an integer first")] @@ -222,11 +224,12 @@ impl From for Diagnostic { | TypeCheckError::TupleIndexOutOfBounds { span, .. } | TypeCheckError::VariableMustBeMutable { span, .. } | TypeCheckError::UnresolvedMethodCall { span, .. } + | TypeCheckError::InvalidComparisonOnField { span } | TypeCheckError::IntegerSignedness { span, .. } | TypeCheckError::IntegerBitWidth { span, .. } | TypeCheckError::InvalidInfixOp { span, .. } | TypeCheckError::InvalidUnaryOp { span, .. } - | TypeCheckError::FieldBitwiseOp { span, .. } + | TypeCheckError::InvalidBitwiseOperationOnField { span, .. } | TypeCheckError::IntegerTypeMismatch { span, .. } | TypeCheckError::FieldComparison { span, .. } | TypeCheckError::AmbiguousBitWidth { span, .. } diff --git a/compiler/noirc_frontend/src/hir/type_check/expr.rs b/compiler/noirc_frontend/src/hir/type_check/expr.rs index b56e2dce2a9..10476b6caef 100644 --- a/compiler/noirc_frontend/src/hir/type_check/expr.rs +++ b/compiler/noirc_frontend/src/hir/type_check/expr.rs @@ -126,7 +126,7 @@ impl<'interner> TypeChecker<'interner> { } } HirLiteral::Bool(_) => Type::Bool, - HirLiteral::Integer(_, _) => self.polymorphic_integer_or_field(), + HirLiteral::Integer(_, _) => Type::polymorphic_integer_or_field(self.interner), HirLiteral::Str(string) => { let len = Type::Constant(string.len() as u64); Type::String(Box::new(len)) @@ -152,16 +152,14 @@ impl<'interner> TypeChecker<'interner> { Ok((typ, use_impl)) => { if use_impl { let id = infix_expr.trait_method_id; - - // Delay checking the trait constraint until the end of the function. - // Checking it now could bind an unbound type variable to any type - // that implements the trait. - let constraint = crate::hir_def::traits::TraitConstraint { - typ: lhs_type.clone(), - trait_id: id.trait_id, - trait_generics: Vec::new(), - }; - self.trait_constraints.push((constraint, *expr_id)); + // Assume operators have no trait generics + self.verify_trait_constraint( + &lhs_type, + id.trait_id, + &[], + *expr_id, + span, + ); self.typecheck_operator_method(*expr_id, id, &lhs_type, span); } typ @@ -418,28 +416,23 @@ impl<'interner> TypeChecker<'interner> { self.interner.select_impl_for_expression(function_ident_id, impl_kind); } Err(erroring_constraints) => { - if erroring_constraints.is_empty() { - self.errors.push(TypeCheckError::TypeAnnotationsNeeded { span }); - } else { - // Don't show any errors where try_get_trait returns None. - // This can happen if a trait is used that was never declared. - let constraints = erroring_constraints - .into_iter() - .map(|constraint| { - let r#trait = self.interner.try_get_trait(constraint.trait_id)?; - let mut name = r#trait.name.to_string(); - if !constraint.trait_generics.is_empty() { - let generics = - vecmap(&constraint.trait_generics, ToString::to_string); - name += &format!("<{}>", generics.join(", ")); - } - Some((constraint.typ, name)) - }) - .collect::>>(); + // Don't show any errors where try_get_trait returns None. + // This can happen if a trait is used that was never declared. + let constraints = erroring_constraints + .into_iter() + .map(|constraint| { + let r#trait = self.interner.try_get_trait(constraint.trait_id)?; + let mut name = r#trait.name.to_string(); + if !constraint.trait_generics.is_empty() { + let generics = vecmap(&constraint.trait_generics, ToString::to_string); + name += &format!("<{}>", generics.join(", ")); + } + Some((constraint.typ, name)) + }) + .collect::>>(); - if let Some(constraints) = constraints { - self.errors.push(TypeCheckError::NoMatchingImplFound { constraints, span }); - } + if let Some(constraints) = constraints { + self.errors.push(TypeCheckError::NoMatchingImplFound { constraints, span }); } } } @@ -565,13 +558,15 @@ impl<'interner> TypeChecker<'interner> { let index_type = self.check_expression(&index_expr.index); let span = self.interner.expr_span(&index_expr.index); - index_type.unify(&self.polymorphic_integer_or_field(), &mut self.errors, || { - TypeCheckError::TypeMismatch { + index_type.unify( + &Type::polymorphic_integer_or_field(self.interner), + &mut self.errors, + || TypeCheckError::TypeMismatch { expected_typ: "an integer".to_owned(), expr_typ: index_type.to_string(), expr_span: span, - } - }); + }, + ); // When writing `a[i]`, if `a : &mut ...` then automatically dereference `a` as many // times as needed to get the underlying array. @@ -841,10 +836,6 @@ impl<'interner> TypeChecker<'interner> { match (lhs_type, rhs_type) { // Avoid reporting errors multiple times (Error, _) | (_, Error) => Ok((Bool, false)), - (Alias(alias, args), other) | (other, Alias(alias, args)) => { - let alias = alias.borrow().get_type(args); - self.comparator_operand_type_rules(&alias, other, op, span) - } // Matches on TypeVariable must be first to follow any type // bindings. @@ -853,8 +844,12 @@ impl<'interner> TypeChecker<'interner> { return self.comparator_operand_type_rules(other, binding, op, span); } - let use_impl = self.bind_type_variables_for_infix(lhs_type, op, rhs_type, span); - Ok((Bool, use_impl)) + self.bind_type_variables_for_infix(lhs_type, op, rhs_type, span); + Ok((Bool, false)) + } + (Alias(alias, args), other) | (other, Alias(alias, args)) => { + let alias = alias.borrow().get_type(args); + self.comparator_operand_type_rules(&alias, other, op, span) } (Integer(sign_x, bit_width_x), Integer(sign_y, bit_width_y)) => { if sign_x != sign_y { @@ -1084,16 +1079,13 @@ impl<'interner> TypeChecker<'interner> { } } - /// Handles the TypeVariable case for checking binary operators. - /// Returns true if we should use the impl for the operator instead of the primitive - /// version of it. fn bind_type_variables_for_infix( &mut self, lhs_type: &Type, op: &HirBinaryOp, rhs_type: &Type, span: Span, - ) -> bool { + ) { self.unify(lhs_type, rhs_type, || TypeCheckError::TypeMismatchWithSource { expected: lhs_type.clone(), actual: rhs_type.clone(), @@ -1101,26 +1093,22 @@ impl<'interner> TypeChecker<'interner> { span, }); - let use_impl = !lhs_type.is_numeric(); - - // If this operator isn't valid for fields we have to possibly narrow - // TypeVariableKind::IntegerOrField to TypeVariableKind::Integer. - // Doing so also ensures a type error if Field is used. - // The is_numeric check is to allow impls for custom types to bypass this. - if !op.kind.is_valid_for_field_type() && lhs_type.is_numeric() { - let target = Type::polymorphic_integer(self.interner); - - use BinaryOpKind::*; - use TypeCheckError::*; - self.unify(lhs_type, &target, || match op.kind { - Less | LessEqual | Greater | GreaterEqual => FieldComparison { span }, - And | Or | Xor | ShiftRight | ShiftLeft => FieldBitwiseOp { span }, - Modulo => FieldModulo { span }, - other => unreachable!("Operator {other:?} should be valid for Field"), - }); - } + // In addition to unifying both types, we also have to bind either + // the lhs or rhs to an integer type variable. This ensures if both lhs + // and rhs are type variables, that they will have the correct integer + // type variable kind instead of TypeVariableKind::Normal. + let target = if op.kind.is_valid_for_field_type() { + Type::polymorphic_integer_or_field(self.interner) + } else { + Type::polymorphic_integer(self.interner) + }; - use_impl + self.unify(lhs_type, &target, || TypeCheckError::TypeMismatchWithSource { + expected: lhs_type.clone(), + actual: rhs_type.clone(), + source: Source::Binary, + span, + }); } // Given a binary operator and another type. This method will produce the output type @@ -1142,10 +1130,6 @@ impl<'interner> TypeChecker<'interner> { match (lhs_type, rhs_type) { // An error type on either side will always return an error (Error, _) | (_, Error) => Ok((Error, false)), - (Alias(alias, args), other) | (other, Alias(alias, args)) => { - let alias = alias.borrow().get_type(args); - self.infix_operand_type_rules(&alias, op, other, span) - } // Matches on TypeVariable must be first so that we follow any type // bindings. @@ -1154,8 +1138,14 @@ impl<'interner> TypeChecker<'interner> { return self.infix_operand_type_rules(binding, op, other, span); } - let use_impl = self.bind_type_variables_for_infix(lhs_type, op, rhs_type, span); - Ok((other.clone(), use_impl)) + self.bind_type_variables_for_infix(lhs_type, op, rhs_type, span); + + // Both types are unified so the choice of which to return is arbitrary + Ok((other.clone(), false)) + } + (Alias(alias, args), other) | (other, Alias(alias, args)) => { + let alias = alias.borrow().get_type(args); + self.infix_operand_type_rules(&alias, op, other, span) } (Integer(sign_x, bit_width_x), Integer(sign_y, bit_width_y)) => { if sign_x != sign_y { @@ -1180,7 +1170,7 @@ impl<'interner> TypeChecker<'interner> { if op.kind == BinaryOpKind::Modulo { return Err(TypeCheckError::FieldModulo { span }); } else { - return Err(TypeCheckError::FieldBitwiseOp { span }); + return Err(TypeCheckError::InvalidBitwiseOperationOnField { span }); } } Ok((FieldElement, false)) @@ -1221,7 +1211,7 @@ impl<'interner> TypeChecker<'interner> { self.errors .push(TypeCheckError::InvalidUnaryOp { kind: rhs_type.to_string(), span }); } - let expected = self.polymorphic_integer_or_field(); + let expected = Type::polymorphic_integer_or_field(self.interner); rhs_type.unify(&expected, &mut self.errors, || TypeCheckError::InvalidUnaryOp { kind: rhs_type.to_string(), span, diff --git a/compiler/noirc_frontend/src/hir/type_check/mod.rs b/compiler/noirc_frontend/src/hir/type_check/mod.rs index c5a04c33883..cfac0adcad9 100644 --- a/compiler/noirc_frontend/src/hir/type_check/mod.rs +++ b/compiler/noirc_frontend/src/hir/type_check/mod.rs @@ -37,11 +37,6 @@ pub struct TypeChecker<'interner> { /// on each variable, but it is only until function calls when the types /// needed for the trait constraint may become known. trait_constraints: Vec<(TraitConstraint, ExprId)>, - - /// All type variables created in the current function. - /// This map is used to default any integer type variables at the end of - /// a function (before checking trait constraints) if a type wasn't already chosen. - type_variables: Vec, } /// Type checks a function and assigns the @@ -91,13 +86,31 @@ pub fn type_check_func(interner: &mut NodeInterner, func_id: FuncId) -> Vec Vec Vec Vec TypeChecker<'interner> { fn new(interner: &'interner mut NodeInterner) -> Self { - Self { - interner, - errors: Vec::new(), - trait_constraints: Vec::new(), - type_variables: Vec::new(), - current_function: None, - } + Self { interner, errors: Vec::new(), trait_constraints: Vec::new(), current_function: None } } fn check_function_body(&mut self, body: &ExprId) -> Type { @@ -369,7 +350,6 @@ impl<'interner> TypeChecker<'interner> { interner, errors: Vec::new(), trait_constraints: Vec::new(), - type_variables: Vec::new(), current_function: None, }; let statement = this.interner.get_global(id).let_statement; @@ -403,22 +383,6 @@ impl<'interner> TypeChecker<'interner> { make_error, ); } - - /// Return a fresh integer or field type variable and log it - /// in self.type_variables to default it later. - fn polymorphic_integer_or_field(&mut self) -> Type { - let typ = Type::polymorphic_integer_or_field(self.interner); - self.type_variables.push(typ.clone()); - typ - } - - /// Return a fresh integer type variable and log it - /// in self.type_variables to default it later. - fn polymorphic_integer(&mut self) -> Type { - let typ = Type::polymorphic_integer(self.interner); - self.type_variables.push(typ.clone()); - typ - } } // XXX: These tests are all manual currently. @@ -502,6 +466,7 @@ mod test { pattern: Identifier(z), r#type: Type::FieldElement, expression: expr_id, + attributes: vec![], }; let stmt_id = interner.push_stmt(HirStatement::Let(let_stmt)); let expr_id = interner diff --git a/compiler/noirc_frontend/src/hir/type_check/stmt.rs b/compiler/noirc_frontend/src/hir/type_check/stmt.rs index fb57aa75f89..69363d5f00a 100644 --- a/compiler/noirc_frontend/src/hir/type_check/stmt.rs +++ b/compiler/noirc_frontend/src/hir/type_check/stmt.rs @@ -1,5 +1,5 @@ use iter_extended::vecmap; -use noirc_errors::Span; +use noirc_errors::{Location, Span}; use crate::hir_def::expr::{HirExpression, HirIdent, HirLiteral}; use crate::hir_def::stmt::{ @@ -71,7 +71,7 @@ impl<'interner> TypeChecker<'interner> { expr_span: range_span, }); - let expected_type = self.polymorphic_integer(); + let expected_type = Type::polymorphic_integer(self.interner); self.unify(&start_range_type, &expected_type, || TypeCheckError::TypeCannotBeUsed { typ: start_range_type.clone(), @@ -195,51 +195,51 @@ impl<'interner> TypeChecker<'interner> { (typ.clone(), HirLValue::Ident(ident.clone(), typ), mutable) } - HirLValue::MemberAccess { object, field_name, location, .. } => { + HirLValue::MemberAccess { object, field_name, .. } => { let (lhs_type, object, mut mutable) = self.check_lvalue(object, assign_span); let mut object = Box::new(object); + let span = field_name.span(); let field_name = field_name.clone(); let object_ref = &mut object; let mutable_ref = &mut mutable; - let location = *location; let dereference_lhs = move |_: &mut Self, _, element_type| { // We must create a temporary value first to move out of object_ref before // we eventually reassign to it. let id = DefinitionId::dummy_id(); + let location = Location::new(span, fm::FileId::dummy()); let ident = HirIdent::non_trait_method(id, location); let tmp_value = HirLValue::Ident(ident, Type::Error); let lvalue = std::mem::replace(object_ref, Box::new(tmp_value)); - *object_ref = - Box::new(HirLValue::Dereference { lvalue, element_type, location }); + *object_ref = Box::new(HirLValue::Dereference { lvalue, element_type }); *mutable_ref = true; }; let name = &field_name.0.contents; let (object_type, field_index) = self - .check_field_access(&lhs_type, name, field_name.span(), Some(dereference_lhs)) + .check_field_access(&lhs_type, name, span, Some(dereference_lhs)) .unwrap_or((Type::Error, 0)); let field_index = Some(field_index); let typ = object_type.clone(); - let lvalue = - HirLValue::MemberAccess { object, field_name, field_index, typ, location }; + let lvalue = HirLValue::MemberAccess { object, field_name, field_index, typ }; (object_type, lvalue, mutable) } - HirLValue::Index { array, index, location, .. } => { + HirLValue::Index { array, index, .. } => { let index_type = self.check_expression(index); let expr_span = self.interner.expr_span(index); - let location = *location; - index_type.unify(&self.polymorphic_integer_or_field(), &mut self.errors, || { - TypeCheckError::TypeMismatch { + index_type.unify( + &Type::polymorphic_integer_or_field(self.interner), + &mut self.errors, + || TypeCheckError::TypeMismatch { expected_typ: "an integer".to_owned(), expr_typ: index_type.to_string(), expr_span, - } - }); + }, + ); let (mut lvalue_type, mut lvalue, mut mutable) = self.check_lvalue(array, assign_span); @@ -248,8 +248,7 @@ impl<'interner> TypeChecker<'interner> { // as needed to unwrap any &mut wrappers. while let Type::MutableReference(element) = lvalue_type.follow_bindings() { let element_type = element.as_ref().clone(); - lvalue = - HirLValue::Dereference { lvalue: Box::new(lvalue), element_type, location }; + lvalue = HirLValue::Dereference { lvalue: Box::new(lvalue), element_type }; lvalue_type = *element; // We know this value to be mutable now since we found an `&mut` mutable = true; @@ -276,12 +275,11 @@ impl<'interner> TypeChecker<'interner> { }; let array = Box::new(lvalue); - (typ.clone(), HirLValue::Index { array, index: *index, typ, location }, mutable) + (typ.clone(), HirLValue::Index { array, index: *index, typ }, mutable) } - HirLValue::Dereference { lvalue, element_type: _, location } => { + HirLValue::Dereference { lvalue, element_type: _ } => { let (reference_type, lvalue, _) = self.check_lvalue(lvalue, assign_span); let lvalue = Box::new(lvalue); - let location = *location; let element_type = Type::type_variable(self.interner.next_type_variable_id()); let expected_type = Type::MutableReference(Box::new(element_type.clone())); @@ -293,11 +291,7 @@ impl<'interner> TypeChecker<'interner> { }); // Dereferences are always mutable since we already type checked against a &mut T - ( - element_type.clone(), - HirLValue::Dereference { lvalue, element_type, location }, - true, - ) + (element_type.clone(), HirLValue::Dereference { lvalue, element_type }, true) } } } diff --git a/compiler/noirc_frontend/src/hir_def/stmt.rs b/compiler/noirc_frontend/src/hir_def/stmt.rs index c5e287b393c..21fda446bfa 100644 --- a/compiler/noirc_frontend/src/hir_def/stmt.rs +++ b/compiler/noirc_frontend/src/hir_def/stmt.rs @@ -1,4 +1,5 @@ use super::expr::HirIdent; +use crate::macros_api::SecondaryAttribute; use crate::node_interner::ExprId; use crate::{Ident, Type}; use fm::FileId; @@ -26,6 +27,7 @@ pub struct HirLetStatement { pub pattern: HirPattern, pub r#type: Type, pub expression: ExprId, + pub attributes: Vec, } impl HirLetStatement { @@ -99,15 +101,6 @@ impl HirPattern { | HirPattern::Struct(_, _, location) => location.span, } } - - pub(crate) fn location(&self) -> Location { - match self { - HirPattern::Identifier(ident) => ident.location, - HirPattern::Mutable(_, location) - | HirPattern::Tuple(_, location) - | HirPattern::Struct(_, _, location) => *location, - } - } } /// Represents an Ast form that can be assigned to. These @@ -120,17 +113,14 @@ pub enum HirLValue { field_name: Ident, field_index: Option, typ: Type, - location: Location, }, Index { array: Box, index: ExprId, typ: Type, - location: Location, }, Dereference { lvalue: Box, element_type: Type, - location: Location, }, } diff --git a/compiler/noirc_frontend/src/hir_def/types.rs b/compiler/noirc_frontend/src/hir_def/types.rs index ec8b54c33b8..65592407d7d 100644 --- a/compiler/noirc_frontend/src/hir_def/types.rs +++ b/compiler/noirc_frontend/src/hir_def/types.rs @@ -543,11 +543,11 @@ impl TypeBinding { pub struct TypeVariableId(pub usize); impl Type { - pub fn default_int_or_field_type() -> Type { + pub fn default_int_type() -> Type { Type::FieldElement } - pub fn default_int_type() -> Type { + pub fn default_range_loop_type() -> Type { Type::Integer(Signedness::Unsigned, IntegerBitSize::SixtyFour) } @@ -589,7 +589,6 @@ impl Type { TypeBinding::Bound(binding) => binding.is_bindable(), TypeBinding::Unbound(_) => true, }, - Type::Alias(alias, args) => alias.borrow().get_type(args).is_bindable(), _ => false, } } @@ -606,15 +605,6 @@ impl Type { matches!(self.follow_bindings(), Type::Integer(Signedness::Unsigned, _)) } - pub fn is_numeric(&self) -> bool { - use Type::*; - use TypeVariableKind as K; - matches!( - self.follow_bindings(), - FieldElement | Integer(..) | Bool | TypeVariable(_, K::Integer | K::IntegerOrField) - ) - } - fn contains_numeric_typevar(&self, target_id: TypeVariableId) -> bool { // True if the given type is a NamedGeneric with the target_id let named_generic_id_matches_target = |typ: &Type| { @@ -787,7 +777,7 @@ impl std::fmt::Display for Type { Type::TypeVariable(var, TypeVariableKind::Normal) => write!(f, "{}", var.borrow()), Type::TypeVariable(binding, TypeVariableKind::Integer) => { if let TypeBinding::Unbound(_) = &*binding.borrow() { - write!(f, "{}", Type::default_int_type()) + write!(f, "{}", TypeVariableKind::Integer.default_type()) } else { write!(f, "{}", binding.borrow()) } @@ -1706,12 +1696,11 @@ impl BinaryTypeOperator { impl TypeVariableKind { /// Returns the default type this type variable should be bound to if it is still unbound /// during monomorphization. - pub(crate) fn default_type(&self) -> Option { + pub(crate) fn default_type(&self) -> Type { match self { - TypeVariableKind::IntegerOrField => Some(Type::default_int_or_field_type()), - TypeVariableKind::Integer => Some(Type::default_int_type()), - TypeVariableKind::Constant(length) => Some(Type::Constant(*length)), - TypeVariableKind::Normal => None, + TypeVariableKind::IntegerOrField | TypeVariableKind::Normal => Type::default_int_type(), + TypeVariableKind::Integer => Type::default_range_loop_type(), + TypeVariableKind::Constant(length) => Type::Constant(*length), } } } @@ -1745,12 +1734,12 @@ impl From<&Type> for PrintableType { }, Type::TypeVariable(binding, TypeVariableKind::Integer) => match &*binding.borrow() { TypeBinding::Bound(typ) => typ.into(), - TypeBinding::Unbound(_) => Type::default_int_type().into(), + TypeBinding::Unbound(_) => Type::default_range_loop_type().into(), }, Type::TypeVariable(binding, TypeVariableKind::IntegerOrField) => { match &*binding.borrow() { TypeBinding::Bound(typ) => typ.into(), - TypeBinding::Unbound(_) => Type::default_int_or_field_type().into(), + TypeBinding::Unbound(_) => Type::default_int_type().into(), } } Type::Bool => PrintableType::Boolean, diff --git a/compiler/noirc_frontend/src/lexer/lexer.rs b/compiler/noirc_frontend/src/lexer/lexer.rs index c4b6bb288dc..363ca767a89 100644 --- a/compiler/noirc_frontend/src/lexer/lexer.rs +++ b/compiler/noirc_frontend/src/lexer/lexer.rs @@ -1097,114 +1097,4 @@ mod tests { assert_eq!(got, token); } } - - // returns a vector of: - // (expected_token_discriminator, strings_to_lex) - // expected_token_discriminator matches a given token when - // std::mem::discriminant returns the same discriminant for both. - fn blns_base64_to_statements(base64_str: String) -> Vec<(Option, Vec)> { - use base64::engine::general_purpose; - use std::borrow::Cow; - use std::io::Cursor; - use std::io::Read; - - let mut wrapped_reader = Cursor::new(base64_str); - let mut decoder = - base64::read::DecoderReader::new(&mut wrapped_reader, &general_purpose::STANDARD); - let mut base64_decoded = Vec::new(); - decoder.read_to_end(&mut base64_decoded).unwrap(); - - // NOTE: when successful, this is the same conversion method as used in - // noirc_driver::stdlib::stdlib_paths_with_source, viz. - // - // let source = std::str::from_utf8(..).unwrap().to_string(); - let s: Cow<'_, str> = match std::str::from_utf8(&base64_decoded) { - Ok(s) => std::borrow::Cow::Borrowed(s), - Err(_err) => { - // recover as much of the string as possible - // when str::from_utf8 fails - String::from_utf8_lossy(&base64_decoded) - } - }; - - vec![ - // Token::Ident(_) - (None, vec![format!("let \"{s}\" = ();")]), - (Some(Token::Str("".to_string())), vec![format!("let s = \"{s}\";")]), - ( - Some(Token::RawStr("".to_string(), 0)), - vec![ - // let s = r"Hello world"; - format!("let s = r\"{s}\";"), - // let s = r#"Simon says "hello world""#; - format!("let s = r#\"{s}\"#;"), - // // Any number of hashes may be used (>= 1) as long as the string also terminates with the same number of hashes - // let s = r#####"One "#, Two "##, Three "###, Four "####, Five will end the string."#####; - format!("let s = r##\"{s}\"##;"), - format!("let s = r###\"{s}\"###;"), - format!("let s = r####\"{s}\"####; "), - format!("let s = r#####\"{s}\"#####;"), - ], - ), - (Some(Token::FmtStr("".to_string())), vec![format!("assert(x == y, f\"{s}\");")]), - // expected token not found - // (Some(Token::LineComment("".to_string(), None)), vec![ - (None, vec![format!("//{s}"), format!("// {s}")]), - // expected token not found - // (Some(Token::BlockComment("".to_string(), None)), vec![ - (None, vec![format!("/*{s}*/"), format!("/* {s} */"), format!("/*\n{s}\n*/")]), - ] - } - - #[test] - fn test_big_list_of_naughty_strings() { - use std::mem::discriminant; - - let blns_contents = include_str!(env!("BLNS_JSON_PATH")); - let blns_base64: Vec = - serde_json::from_str(blns_contents).expect("BLNS json invalid"); - for blns_base64_str in blns_base64 { - let statements = blns_base64_to_statements(blns_base64_str); - for (token_discriminator_opt, blns_program_strs) in statements { - for blns_program_str in blns_program_strs { - let mut expected_token_found = false; - let mut lexer = Lexer::new(&blns_program_str); - let mut result_tokens = Vec::new(); - loop { - match lexer.next_token() { - Ok(next_token) => { - result_tokens.push(next_token.clone()); - expected_token_found |= token_discriminator_opt - .as_ref() - .map(|token_discriminator| { - discriminant(token_discriminator) - == discriminant(&next_token.token()) - }) - .unwrap_or(true); - - if next_token == Token::EOF { - assert!(lexer.done, "lexer not done when EOF emitted!"); - break; - } - } - - Err(LexerErrorKind::InvalidIntegerLiteral { .. }) - | Err(LexerErrorKind::UnexpectedCharacter { .. }) - | Err(LexerErrorKind::UnterminatedBlockComment { .. }) => { - expected_token_found = true; - } - Err(err) => { - panic!("Unexpected lexer error found: {:?}", err) - } - } - } - - assert!( - expected_token_found, - "expected token not found: {token_discriminator_opt:?}\noutput:\n{result_tokens:?}", - ); - } - } - } - } } diff --git a/compiler/noirc_frontend/src/lexer/token.rs b/compiler/noirc_frontend/src/lexer/token.rs index f8378cdd84b..357b1ead593 100644 --- a/compiler/noirc_frontend/src/lexer/token.rs +++ b/compiler/noirc_frontend/src/lexer/token.rs @@ -510,6 +510,7 @@ impl Attribute { Attribute::Secondary(SecondaryAttribute::ContractLibraryMethod) } ["event"] => Attribute::Secondary(SecondaryAttribute::Event), + ["abi", tag] => Attribute::Secondary(SecondaryAttribute::Abi(tag.to_string())), ["export"] => Attribute::Secondary(SecondaryAttribute::Export), ["deprecated", name] => { if !name.starts_with('"') && !name.ends_with('"') { @@ -604,6 +605,7 @@ pub enum SecondaryAttribute { Export, Field(String), Custom(String), + Abi(String), } impl fmt::Display for SecondaryAttribute { @@ -618,6 +620,7 @@ impl fmt::Display for SecondaryAttribute { SecondaryAttribute::Event => write!(f, "#[event]"), SecondaryAttribute::Export => write!(f, "#[export]"), SecondaryAttribute::Field(ref k) => write!(f, "#[field({k})]"), + SecondaryAttribute::Abi(ref k) => write!(f, "#[abi({k})]"), } } } @@ -640,7 +643,9 @@ impl AsRef for SecondaryAttribute { match self { SecondaryAttribute::Deprecated(Some(string)) => string, SecondaryAttribute::Deprecated(None) => "", - SecondaryAttribute::Custom(string) | SecondaryAttribute::Field(string) => string, + SecondaryAttribute::Custom(string) + | SecondaryAttribute::Field(string) + | SecondaryAttribute::Abi(string) => string, SecondaryAttribute::ContractLibraryMethod => "", SecondaryAttribute::Event | SecondaryAttribute::Export => "", } diff --git a/compiler/noirc_frontend/src/monomorphization/errors.rs b/compiler/noirc_frontend/src/monomorphization/errors.rs deleted file mode 100644 index 3011c26cffe..00000000000 --- a/compiler/noirc_frontend/src/monomorphization/errors.rs +++ /dev/null @@ -1,39 +0,0 @@ -use thiserror::Error; - -use noirc_errors::{CustomDiagnostic, FileDiagnostic, Location}; - -#[derive(Debug, Error)] -pub enum MonomorphizationError { - #[error("Length of generic array could not be determined.")] - UnknownArrayLength { location: Location }, - - #[error("Type annotations needed")] - TypeAnnotationsNeeded { location: Location }, -} - -impl MonomorphizationError { - fn location(&self) -> Location { - match self { - MonomorphizationError::UnknownArrayLength { location } - | MonomorphizationError::TypeAnnotationsNeeded { location } => *location, - } - } -} - -impl From for FileDiagnostic { - fn from(error: MonomorphizationError) -> FileDiagnostic { - let location = error.location(); - let call_stack = vec![location]; - let diagnostic = error.into_diagnostic(); - diagnostic.in_file(location.file).with_call_stack(call_stack) - } -} - -impl MonomorphizationError { - fn into_diagnostic(self) -> CustomDiagnostic { - let message = self.to_string(); - let location = self.location(); - - CustomDiagnostic::simple_error(message, String::new(), location.span) - } -} diff --git a/compiler/noirc_frontend/src/monomorphization/mod.rs b/compiler/noirc_frontend/src/monomorphization/mod.rs index 6aa0abce152..c6ab681db6c 100644 --- a/compiler/noirc_frontend/src/monomorphization/mod.rs +++ b/compiler/noirc_frontend/src/monomorphization/mod.rs @@ -8,6 +8,16 @@ //! //! The entry point to this pass is the `monomorphize` function which, starting from a given //! function, will monomorphize the entire reachable program. +use acvm::FieldElement; +use iter_extended::{btree_map, try_vecmap, vecmap}; +use noirc_errors::{CustomDiagnostic, FileDiagnostic, Location}; +use noirc_printable_type::PrintableType; +use std::{ + collections::{BTreeMap, HashMap, VecDeque}, + unreachable, +}; +use thiserror::Error; + use crate::{ debug::DebugInstrumenter, hir_def::{ @@ -21,25 +31,13 @@ use crate::{ FunctionKind, IntegerBitSize, Signedness, Type, TypeBinding, TypeBindings, TypeVariable, TypeVariableKind, UnaryOp, Visibility, }; -use acvm::FieldElement; -use iter_extended::{btree_map, try_vecmap, vecmap}; -use noirc_errors::Location; -use noirc_printable_type::PrintableType; -use std::{ - collections::{BTreeMap, HashMap, VecDeque}, - unreachable, -}; +use self::ast::{Definition, FuncId, Function, LocalId, Program}; use self::debug_types::DebugTypeTracker; -use self::{ - ast::{Definition, FuncId, Function, LocalId, Program}, - errors::MonomorphizationError, -}; pub mod ast; mod debug; pub mod debug_types; -pub mod errors; pub mod printer; struct LambdaContext { @@ -90,6 +88,40 @@ struct Monomorphizer<'interner> { type HirType = crate::Type; +#[derive(Debug, Error)] +pub enum MonomorphizationError { + #[error("Length of generic array could not be determined.")] + UnknownArrayLength { location: Location }, +} + +impl MonomorphizationError { + fn call_stack(&self) -> Vec { + match self { + MonomorphizationError::UnknownArrayLength { location } => vec![*location], + } + } +} + +impl From for FileDiagnostic { + fn from(error: MonomorphizationError) -> FileDiagnostic { + let call_stack = error.call_stack(); + let file_id = call_stack.last().map(|location| location.file).unwrap_or_default(); + let diagnostic = error.into_diagnostic(); + diagnostic.in_file(file_id).with_call_stack(call_stack) + } +} + +impl MonomorphizationError { + fn into_diagnostic(self) -> CustomDiagnostic { + CustomDiagnostic::simple_error( + "Internal Consistency Evaluators Errors: \n + This is likely a bug. Consider opening an issue at https://github.com/noir-lang/noir/issues".to_owned(), + self.to_string(), + noirc_errors::Span::inclusive(0, 0) + ) + } +} + /// Starting from the given `main` function, monomorphize the entire program, /// replacing all references to type variables and NamedGenerics with concrete /// types, duplicating definitions as necessary to do so. @@ -291,17 +323,15 @@ impl<'interner> Monomorphizer<'interner> { let body_expr_id = *self.interner.function(&f).as_expr(); let body_return_type = self.interner.id_type(body_expr_id); - let return_type = match meta.return_type() { + let return_type = self.convert_type(match meta.return_type() { Type::TraitAsType(..) => &body_return_type, - other => other, - }; - - let return_type = Self::convert_type(return_type, meta.location)?; + _ => meta.return_type(), + }); let unconstrained = modifiers.is_unconstrained; let should_fold = meta.should_fold; - let parameters = self.parameters(&meta.parameters)?; + let parameters = self.parameters(&meta.parameters); let body = self.expr(body_expr_id)?; let function = ast::Function { id, @@ -325,15 +355,12 @@ impl<'interner> Monomorphizer<'interner> { /// Monomorphize each parameter, expanding tuple/struct patterns into multiple parameters /// and binding any generic types found. - fn parameters( - &mut self, - params: &Parameters, - ) -> Result, MonomorphizationError> { + fn parameters(&mut self, params: &Parameters) -> Vec<(ast::LocalId, bool, String, ast::Type)> { let mut new_params = Vec::with_capacity(params.len()); for (parameter, typ, _) in ¶ms.0 { - self.parameter(parameter, typ, &mut new_params)?; + self.parameter(parameter, typ, &mut new_params); } - Ok(new_params) + new_params } fn parameter( @@ -341,22 +368,21 @@ impl<'interner> Monomorphizer<'interner> { param: &HirPattern, typ: &HirType, new_params: &mut Vec<(ast::LocalId, bool, String, ast::Type)>, - ) -> Result<(), MonomorphizationError> { + ) { match param { HirPattern::Identifier(ident) => { let new_id = self.next_local_id(); let definition = self.interner.definition(ident.id); let name = definition.name.clone(); - let typ = Self::convert_type(typ, ident.location)?; - new_params.push((new_id, definition.mutable, name, typ)); + new_params.push((new_id, definition.mutable, name, self.convert_type(typ))); self.define_local(ident.id, new_id); } - HirPattern::Mutable(pattern, _) => self.parameter(pattern, typ, new_params)?, + HirPattern::Mutable(pattern, _) => self.parameter(pattern, typ, new_params), HirPattern::Tuple(fields, _) => { let tuple_field_types = unwrap_tuple_type(typ); for (field, typ) in fields.iter().zip(tuple_field_types) { - self.parameter(field, &typ, new_params)?; + self.parameter(field, &typ, new_params); } } HirPattern::Struct(_, fields, _) => { @@ -373,11 +399,10 @@ impl<'interner> Monomorphizer<'interner> { unreachable!("Expected a field named '{field_name}' in the struct pattern") }); - self.parameter(field, &field_type, new_params)?; + self.parameter(field, &field_type, new_params); } } } - Ok(()) } fn expr( @@ -400,10 +425,9 @@ impl<'interner> Monomorphizer<'interner> { } HirExpression::Literal(HirLiteral::Bool(value)) => Literal(Bool(value)), HirExpression::Literal(HirLiteral::Integer(value, sign)) => { - let location = self.interner.id_location(expr); - let typ = Self::convert_type(&self.interner.id_type(expr), location)?; - if sign { + let typ = self.convert_type(&self.interner.id_type(expr)); + let location = self.interner.id_location(expr); match typ { ast::Type::Field => Literal(Integer(-value, typ, location)), ast::Type::Integer(_, bit_size) => { @@ -414,6 +438,8 @@ impl<'interner> Monomorphizer<'interner> { _ => unreachable!("Integer literal must be numeric"), } } else { + let typ = self.convert_type(&self.interner.id_type(expr)); + let location = self.interner.id_location(expr); Literal(Integer(value, typ, location)) } } @@ -437,7 +463,7 @@ impl<'interner> Monomorphizer<'interner> { ast::Expression::Unary(ast::Unary { operator: prefix.operator, rhs: Box::new(self.expr(prefix.rhs)?), - result_type: Self::convert_type(&self.interner.id_type(expr), location)?, + result_type: self.convert_type(&self.interner.id_type(expr)), location, }) } @@ -466,8 +492,8 @@ impl<'interner> Monomorphizer<'interner> { let function_type = Type::Function(args, Box::new(ret.clone()), env); let method = infix.trait_method_id; - let func = self.resolve_trait_method_reference(expr, function_type, method)?; - self.create_operator_impl_call(func, lhs, infix.operator, rhs, ret, location)? + let func = self.resolve_trait_method_reference(expr, function_type, method); + self.create_operator_impl_call(func, lhs, infix.operator, rhs, ret, location) } else { let lhs = Box::new(lhs); let rhs = Box::new(rhs); @@ -485,22 +511,23 @@ impl<'interner> Monomorphizer<'interner> { HirExpression::Call(call) => self.function_call(call, expr)?, - HirExpression::Cast(cast) => { - let location = self.interner.expr_location(&expr); - let typ = Self::convert_type(&cast.r#type, location)?; - let lhs = Box::new(self.expr(cast.lhs)?); - ast::Expression::Cast(ast::Cast { lhs, r#type: typ, location }) - } + HirExpression::Cast(cast) => ast::Expression::Cast(ast::Cast { + lhs: Box::new(self.expr(cast.lhs)?), + r#type: self.convert_type(&cast.r#type), + location: self.interner.expr_location(&expr), + }), HirExpression::If(if_expr) => { - let condition = Box::new(self.expr(if_expr.condition)?); - let consequence = Box::new(self.expr(if_expr.consequence)?); + let cond = self.expr(if_expr.condition)?; + let then = self.expr(if_expr.consequence)?; let else_ = if_expr.alternative.map(|alt| self.expr(alt)).transpose()?.map(Box::new); - - let location = self.interner.expr_location(&expr); - let typ = Self::convert_type(&self.interner.id_type(expr), location)?; - ast::Expression::If(ast::If { condition, consequence, alternative: else_, typ }) + ast::Expression::If(ast::If { + condition: Box::new(cond), + consequence: Box::new(then), + alternative: else_, + typ: self.convert_type(&self.interner.id_type(expr)), + }) } HirExpression::Tuple(fields) => { @@ -527,8 +554,7 @@ impl<'interner> Monomorphizer<'interner> { array_elements: Vec, is_slice: bool, ) -> Result { - let location = self.interner.expr_location(&array); - let typ = Self::convert_type(&self.interner.id_type(array), location)?; + let typ = self.convert_type(&self.interner.id_type(array)); let contents = try_vecmap(array_elements, |id| self.expr(id))?; if is_slice { Ok(ast::Expression::Literal(ast::Literal::Slice(ast::ArrayLiteral { contents, typ }))) @@ -544,8 +570,7 @@ impl<'interner> Monomorphizer<'interner> { length: HirType, is_slice: bool, ) -> Result { - let location = self.interner.expr_location(&array); - let typ = Self::convert_type(&self.interner.id_type(array), location)?; + let typ = self.convert_type(&self.interner.id_type(array)); let length = length.evaluate_to_u64().ok_or_else(|| { let location = self.interner.expr_location(&array); @@ -565,8 +590,7 @@ impl<'interner> Monomorphizer<'interner> { id: node_interner::ExprId, index: HirIndexExpression, ) -> Result { - let location = self.interner.expr_location(&id); - let element_type = Self::convert_type(&self.interner.id_type(id), location)?; + let element_type = self.convert_type(&self.interner.id_type(id)); let collection = Box::new(self.expr(index.collection)?); let index = Box::new(self.expr(index.index)?); @@ -597,14 +621,11 @@ impl<'interner> Monomorphizer<'interner> { self.define_local(for_loop.identifier.id, index_variable); let block = Box::new(self.expr(for_loop.block)?); - let index_location = for_loop.identifier.location; - let index_type = self.interner.id_type(for_loop.start_range); - let index_type = Self::convert_type(&index_type, index_location)?; Ok(ast::Expression::For(ast::For { index_variable, index_name: self.interner.definition_name(for_loop.identifier.id).to_owned(), - index_type, + index_type: self.convert_type(&self.interner.id_type(for_loop.start_range)), start_range: Box::new(start), end_range: Box::new(end), start_range_location: self.interner.expr_location(&for_loop.start_range), @@ -628,7 +649,7 @@ impl<'interner> Monomorphizer<'interner> { ) -> Result { let expr = self.expr(let_statement.expression)?; let expected_type = self.interner.id_type(let_statement.expression); - self.unpack_pattern(let_statement.pattern, expr, &expected_type) + Ok(self.unpack_pattern(let_statement.pattern, expr, &expected_type)) } fn constructor( @@ -649,8 +670,7 @@ impl<'interner> Monomorphizer<'interner> { for (field_name, expr_id) in constructor.fields { let new_id = self.next_local_id(); let field_type = field_type_map.get(&field_name.0.contents).unwrap(); - let location = self.interner.expr_location(&expr_id); - let typ = Self::convert_type(field_type, location)?; + let typ = self.convert_type(field_type); field_vars.insert(field_name.0.contents.clone(), (new_id, typ)); let expression = Box::new(self.expr(expr_id)?); @@ -694,19 +714,19 @@ impl<'interner> Monomorphizer<'interner> { pattern: HirPattern, value: ast::Expression, typ: &HirType, - ) -> Result { + ) -> ast::Expression { match pattern { HirPattern::Identifier(ident) => { let new_id = self.next_local_id(); self.define_local(ident.id, new_id); let definition = self.interner.definition(ident.id); - Ok(ast::Expression::Let(ast::Let { + ast::Expression::Let(ast::Let { id: new_id, mutable: definition.mutable, name: definition.name.clone(), expression: Box::new(value), - })) + }) } HirPattern::Mutable(pattern, _) => self.unpack_pattern(*pattern, value, typ), HirPattern::Tuple(patterns, _) => { @@ -735,7 +755,7 @@ impl<'interner> Monomorphizer<'interner> { &mut self, value: ast::Expression, fields: impl Iterator, - ) -> Result { + ) -> ast::Expression { let fresh_id = self.next_local_id(); let mut definitions = vec![ast::Expression::Let(ast::Let { @@ -746,22 +766,21 @@ impl<'interner> Monomorphizer<'interner> { })]; for (i, (field_pattern, field_type)) in fields.into_iter().enumerate() { - let location = field_pattern.location(); + let location = None; let mutable = false; let definition = Definition::Local(fresh_id); let name = i.to_string(); - let typ = Self::convert_type(&field_type, location)?; + let typ = self.convert_type(&field_type); - let location = Some(location); let new_rhs = ast::Expression::Ident(ast::Ident { location, mutable, definition, name, typ }); let new_rhs = ast::Expression::ExtractTupleField(Box::new(new_rhs), i); - let new_expr = self.unpack_pattern(field_pattern, new_rhs, &field_type)?; + let new_expr = self.unpack_pattern(field_pattern, new_rhs, &field_type); definitions.push(new_expr); } - Ok(ast::Expression::Block(definitions)) + ast::Expression::Block(definitions) } /// Find a captured variable in the innermost closure, and construct an expression @@ -787,20 +806,15 @@ impl<'interner> Monomorphizer<'interner> { } /// A local (ie non-global) ident only - fn local_ident( - &mut self, - ident: &HirIdent, - ) -> Result, MonomorphizationError> { + fn local_ident(&mut self, ident: &HirIdent) -> Option { let definition = self.interner.definition(ident.id); let name = definition.name.clone(); let mutable = definition.mutable; - let Some(definition) = self.lookup_local(ident.id) else { - return Ok(None); - }; + let definition = self.lookup_local(ident.id)?; + let typ = self.convert_type(&self.interner.definition_type(ident.id)); - let typ = Self::convert_type(&self.interner.definition_type(ident.id), ident.location)?; - Ok(Some(ast::Ident { location: Some(ident.location), mutable, definition, name, typ })) + Some(ast::Ident { location: Some(ident.location), mutable, definition, name, typ }) } fn ident( @@ -811,7 +825,7 @@ impl<'interner> Monomorphizer<'interner> { let typ = self.interner.id_type(expr_id); if let ImplKind::TraitMethod(method, _, _) = ident.impl_kind { - return self.resolve_trait_method_reference(expr_id, typ, method); + return Ok(self.resolve_trait_method_reference(expr_id, typ, method)); } let definition = self.interner.definition(ident.id); @@ -821,7 +835,7 @@ impl<'interner> Monomorphizer<'interner> { let location = Some(ident.location); let name = definition.name.clone(); let definition = self.lookup_function(*func_id, expr_id, &typ, None); - let typ = Self::convert_type(&typ, ident.location)?; + let typ = self.convert_type(&typ); let ident = ast::Ident { location, mutable, definition, name, typ: typ.clone() }; let ident_expression = ast::Expression::Ident(ident); if self.is_function_closure_type(&typ) { @@ -844,13 +858,10 @@ impl<'interner> Monomorphizer<'interner> { }; self.expr(let_.expression)? } - DefinitionKind::Local(_) => match self.lookup_captured_expr(ident.id) { - Some(expr) => expr, - None => { - let ident = self.local_ident(&ident)?.unwrap(); - ast::Expression::Ident(ident) - } - }, + DefinitionKind::Local(_) => self.lookup_captured_expr(ident.id).unwrap_or_else(|| { + let ident = self.local_ident(&ident).unwrap(); + ast::Expression::Ident(ident) + }), DefinitionKind::GenericType(type_variable) => { let value = match &*type_variable.borrow() { TypeBinding::Unbound(_) => { @@ -863,7 +874,7 @@ impl<'interner> Monomorphizer<'interner> { let value = FieldElement::from(value as u128); let location = self.interner.id_location(expr_id); - let typ = Self::convert_type(&typ, ident.location)?; + let typ = self.convert_type(&typ); ast::Expression::Literal(ast::Literal::Integer(value, typ, location)) } }; @@ -872,28 +883,26 @@ impl<'interner> Monomorphizer<'interner> { } /// Convert a non-tuple/struct type to a monomorphized type - fn convert_type(typ: &HirType, location: Location) -> Result { - Ok(match typ { + fn convert_type(&self, typ: &HirType) -> ast::Type { + match typ { HirType::FieldElement => ast::Type::Field, HirType::Integer(sign, bits) => ast::Type::Integer(*sign, *bits), HirType::Bool => ast::Type::Bool, HirType::String(size) => ast::Type::String(size.evaluate_to_u64().unwrap_or(0)), HirType::FmtString(size, fields) => { let size = size.evaluate_to_u64().unwrap_or(0); - let fields = Box::new(Self::convert_type(fields.as_ref(), location)?); + let fields = Box::new(self.convert_type(fields.as_ref())); ast::Type::FmtString(size, fields) } HirType::Unit => ast::Type::Unit, HirType::Array(length, element) => { - let element = Box::new(Self::convert_type(element.as_ref(), location)?); - let length = match length.evaluate_to_u64() { - Some(length) => length, - None => return Err(MonomorphizationError::TypeAnnotationsNeeded { location }), - }; + let element = Box::new(self.convert_type(element.as_ref())); + // TODO: convert to MonomorphizationError + let length = length.evaluate_to_u64().unwrap_or(0); ast::Type::Array(length, element) } HirType::Slice(element) => { - let element = Box::new(Self::convert_type(element.as_ref(), location)?); + let element = Box::new(self.convert_type(element.as_ref())); ast::Type::Slice(element) } HirType::TraitAsType(..) => { @@ -901,53 +910,55 @@ impl<'interner> Monomorphizer<'interner> { } HirType::NamedGeneric(binding, _) => { if let TypeBinding::Bound(binding) = &*binding.borrow() { - return Self::convert_type(binding, location); + return self.convert_type(binding); } // Default any remaining unbound type variables. // This should only happen if the variable in question is unused // and within a larger generic type. - binding.bind(HirType::default_int_or_field_type()); + binding.bind(HirType::default_int_type()); ast::Type::Field } HirType::TypeVariable(binding, kind) => { if let TypeBinding::Bound(binding) = &*binding.borrow() { - return Self::convert_type(binding, location); + return self.convert_type(binding); } // Default any remaining unbound type variables. // This should only happen if the variable in question is unused // and within a larger generic type. - let default = match kind.default_type() { - Some(typ) => typ, - None => return Err(MonomorphizationError::TypeAnnotationsNeeded { location }), + let default = if self.is_range_loop + && (matches!(kind, TypeVariableKind::IntegerOrField) + || matches!(kind, TypeVariableKind::Integer)) + { + Type::default_range_loop_type() + } else { + kind.default_type() }; - let monomorphized_default = Self::convert_type(&default, location)?; + let monomorphized_default = self.convert_type(&default); binding.bind(default); monomorphized_default } HirType::Struct(def, args) => { let fields = def.borrow().get_fields(args); - let fields = try_vecmap(fields, |(_, field)| Self::convert_type(&field, location))?; + let fields = vecmap(fields, |(_, field)| self.convert_type(&field)); ast::Type::Tuple(fields) } - HirType::Alias(def, args) => { - Self::convert_type(&def.borrow().get_type(args), location)? - } + HirType::Alias(def, args) => self.convert_type(&def.borrow().get_type(args)), HirType::Tuple(fields) => { - let fields = try_vecmap(fields, |x| Self::convert_type(x, location))?; + let fields = vecmap(fields, |x| self.convert_type(x)); ast::Type::Tuple(fields) } HirType::Function(args, ret, env) => { - let args = try_vecmap(args, |x| Self::convert_type(x, location))?; - let ret = Box::new(Self::convert_type(ret, location)?); - let env = Self::convert_type(env, location)?; + let args = vecmap(args, |x| self.convert_type(x)); + let ret = Box::new(self.convert_type(ret)); + let env = self.convert_type(env); match &env { ast::Type::Unit => ast::Type::Function(args, ret, Box::new(env)), ast::Type::Tuple(_elements) => ast::Type::Tuple(vec![ @@ -963,7 +974,7 @@ impl<'interner> Monomorphizer<'interner> { } HirType::MutableReference(element) => { - let element = Self::convert_type(element, location)?; + let element = self.convert_type(element); ast::Type::MutableReference(Box::new(element)) } @@ -971,7 +982,7 @@ impl<'interner> Monomorphizer<'interner> { unreachable!("Unexpected type {} found", typ) } HirType::Code => unreachable!("Tried to translate Code type into runtime code"), - }) + } } fn is_function_closure(&self, t: ast::Type) -> bool { @@ -1002,7 +1013,7 @@ impl<'interner> Monomorphizer<'interner> { expr_id: node_interner::ExprId, function_type: HirType, method: TraitMethodId, - ) -> Result { + ) -> ast::Expression { let trait_impl = self .interner .get_selected_impl_for_expression(expr_id) @@ -1029,12 +1040,7 @@ impl<'interner> Monomorphizer<'interner> { Err(constraints) => { let failed_constraints = vecmap(constraints, |constraint| { let id = constraint.trait_id; - let mut name = self.interner.get_trait(id).name.to_string(); - if !constraint.trait_generics.is_empty() { - let types = - vecmap(&constraint.trait_generics, |t| format!("{t:?}")); - name += &format!("<{}>", types.join(", ")); - } + let name = self.interner.get_trait(id).name.to_string(); format!(" {}: {name}", constraint.typ) }) .join("\n"); @@ -1051,15 +1057,13 @@ impl<'interner> Monomorphizer<'interner> { }; let the_trait = self.interner.get_trait(method.trait_id); - let location = self.interner.expr_location(&expr_id); - - Ok(ast::Expression::Ident(ast::Ident { + ast::Expression::Ident(ast::Ident { definition: Definition::Function(func_id), mutable: false, location: None, name: the_trait.methods[method.method_index].name.0.contents.clone(), - typ: Self::convert_type(&function_type, location)?, - })) + typ: self.convert_type(&function_type), + }) } fn function_call( @@ -1074,8 +1078,7 @@ impl<'interner> Monomorphizer<'interner> { self.patch_debug_instrumentation_call(&call, &mut arguments)?; let return_type = self.interner.id_type(id); - let location = self.interner.expr_location(&id); - let return_type = Self::convert_type(&return_type, location)?; + let return_type = self.convert_type(&return_type); let location = call.location; @@ -1095,7 +1098,7 @@ impl<'interner> Monomorphizer<'interner> { let mut block_expressions = vec![]; let func_type = self.interner.id_type(call.func); - let func_type = Self::convert_type(&func_type, location)?; + let func_type = self.convert_type(&func_type); let is_closure = self.is_function_closure(func_type); let func = if is_closure { @@ -1117,7 +1120,7 @@ impl<'interner> Monomorphizer<'interner> { definition: Definition::Local(local_id), mutable: false, name: "tmp".to_string(), - typ: Self::convert_type(&self.interner.id_type(call.func), location)?, + typ: self.convert_type(&self.interner.id_type(call.func)), }); let env_argument = @@ -1316,24 +1319,24 @@ impl<'interner> Monomorphizer<'interner> { fn lvalue(&mut self, lvalue: HirLValue) -> Result { let value = match lvalue { - HirLValue::Ident(ident, _) => match self.lookup_captured_lvalue(ident.id) { - Some(value) => value, - None => ast::LValue::Ident(self.local_ident(&ident)?.unwrap()), - }, + HirLValue::Ident(ident, _) => self + .lookup_captured_lvalue(ident.id) + .unwrap_or_else(|| ast::LValue::Ident(self.local_ident(&ident).unwrap())), HirLValue::MemberAccess { object, field_index, .. } => { let field_index = field_index.unwrap(); let object = Box::new(self.lvalue(*object)?); ast::LValue::MemberAccess { object, field_index } } - HirLValue::Index { array, index, typ, location } => { + HirLValue::Index { array, index, typ } => { + let location = self.interner.expr_location(&index); let array = Box::new(self.lvalue(*array)?); let index = Box::new(self.expr(index)?); - let element_type = Self::convert_type(&typ, location)?; + let element_type = self.convert_type(&typ); ast::LValue::Index { array, index, element_type, location } } - HirLValue::Dereference { lvalue, element_type, location } => { + HirLValue::Dereference { lvalue, element_type } => { let reference = Box::new(self.lvalue(*lvalue)?); - let element_type = Self::convert_type(&element_type, location)?; + let element_type = self.convert_type(&element_type); ast::LValue::Dereference { reference, element_type } } }; @@ -1347,7 +1350,7 @@ impl<'interner> Monomorphizer<'interner> { expr: node_interner::ExprId, ) -> Result { if lambda.captures.is_empty() { - self.lambda_no_capture(lambda, expr) + self.lambda_no_capture(lambda) } else { let (setup, closure_variable) = self.lambda_with_setup(lambda, expr)?; Ok(ast::Expression::Block(vec![setup, closure_variable])) @@ -1357,19 +1360,16 @@ impl<'interner> Monomorphizer<'interner> { fn lambda_no_capture( &mut self, lambda: HirLambda, - expr: node_interner::ExprId, ) -> Result { - let location = self.interner.expr_location(&expr); - let ret_type = Self::convert_type(&lambda.return_type, location)?; + let ret_type = self.convert_type(&lambda.return_type); let lambda_name = "lambda"; - let parameter_types = - try_vecmap(&lambda.parameters, |(_, typ)| Self::convert_type(typ, location))?; + let parameter_types = vecmap(&lambda.parameters, |(_, typ)| self.convert_type(typ)); // Manually convert to Parameters type so we can reuse the self.parameters method let parameters = vecmap(lambda.parameters, |(pattern, typ)| (pattern, typ, Visibility::Private)).into(); - let parameters = self.parameters(¶meters)?; + let parameters = self.parameters(¶meters); let body = self.expr(lambda.body)?; let id = self.next_function_id(); @@ -1421,17 +1421,15 @@ impl<'interner> Monomorphizer<'interner> { // patterns in the resulting tree, // which seems more fragile, we directly reuse the return parameters // of this function in those cases - let location = self.interner.expr_location(&expr); - let ret_type = Self::convert_type(&lambda.return_type, location)?; + let ret_type = self.convert_type(&lambda.return_type); let lambda_name = "lambda"; - let parameter_types = - try_vecmap(&lambda.parameters, |(_, typ)| Self::convert_type(typ, location))?; + let parameter_types = vecmap(&lambda.parameters, |(_, typ)| self.convert_type(typ)); // Manually convert to Parameters type so we can reuse the self.parameters method let parameters = vecmap(lambda.parameters, |(pattern, typ)| (pattern, typ, Visibility::Private)).into(); - let mut converted_parameters = self.parameters(¶meters)?; + let mut converted_parameters = self.parameters(¶meters); let id = self.next_function_id(); let name = lambda_name.to_owned(); @@ -1439,27 +1437,26 @@ impl<'interner> Monomorphizer<'interner> { let env_local_id = self.next_local_id(); let env_name = "env"; - let env_tuple = - ast::Expression::Tuple(try_vecmap(&lambda.captures, |capture| { - match capture.transitive_capture_index { - Some(field_index) => { - let lambda_ctx = self.lambda_envs_stack.last().expect( - "Expected to find a parent closure environment, but found none", - ); - - let ident = Box::new(ast::Expression::Ident(lambda_ctx.env_ident.clone())); - Ok(ast::Expression::ExtractTupleField(ident, field_index)) - } - None => { - let ident = self.local_ident(&capture.ident)?.unwrap(); - Ok(ast::Expression::Ident(ident)) - } + let env_tuple = ast::Expression::Tuple(vecmap(&lambda.captures, |capture| { + match capture.transitive_capture_index { + Some(field_index) => match self.lambda_envs_stack.last() { + Some(lambda_ctx) => ast::Expression::ExtractTupleField( + Box::new(ast::Expression::Ident(lambda_ctx.env_ident.clone())), + field_index, + ), + None => unreachable!( + "Expected to find a parent closure environment, but found none" + ), + }, + None => { + let ident = self.local_ident(&capture.ident).unwrap(); + ast::Expression::Ident(ident) } - })?); - + } + })); let expr_type = self.interner.id_type(expr); let env_typ = if let types::Type::Function(_, _, function_env_type) = expr_type { - Self::convert_type(&function_env_type, location)? + self.convert_type(&function_env_type) } else { unreachable!("expected a Function type for a Lambda node") }; @@ -1668,10 +1665,10 @@ impl<'interner> Monomorphizer<'interner> { rhs: ast::Expression, ret: Type, location: Location, - ) -> Result { + ) -> ast::Expression { let arguments = vec![lhs, rhs]; let func = Box::new(func); - let return_type = Self::convert_type(&ret, location)?; + let return_type = self.convert_type(&ret); let mut result = ast::Expression::Call(ast::Call { func, arguments, return_type, location }); @@ -1716,7 +1713,7 @@ impl<'interner> Monomorphizer<'interner> { _ => (), } - Ok(result) + result } /// Call sites are instantiated against the trait method, but when an impl is later selected, diff --git a/compiler/noirc_frontend/src/node_interner.rs b/compiler/noirc_frontend/src/node_interner.rs index dcfceccdb57..4bb6f0bb2e9 100644 --- a/compiler/noirc_frontend/src/node_interner.rs +++ b/compiler/noirc_frontend/src/node_interner.rs @@ -146,6 +146,7 @@ pub struct NodeInterner { // Maps GlobalId -> GlobalInfo // NOTE: currently only used for checking repeat globals and restricting their scope to a module globals: Vec, + global_attributes: HashMap>, next_type_variable_id: std::cell::Cell, @@ -480,6 +481,7 @@ impl Default for NodeInterner { field_indices: HashMap::new(), next_type_variable_id: std::cell::Cell::new(0), globals: Vec::new(), + global_attributes: HashMap::new(), struct_methods: HashMap::new(), primitive_methods: HashMap::new(), type_alias_ref: Vec::new(), @@ -647,11 +649,13 @@ impl NodeInterner { local_id: LocalModuleId, let_statement: StmtId, file: FileId, + attributes: Vec, ) -> GlobalId { 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, false, DefinitionKind::Global(id), location); + self.globals.push(GlobalInfo { id, definition_id, @@ -660,6 +664,7 @@ impl NodeInterner { let_statement, location, }); + self.global_attributes.insert(id, attributes); id } @@ -673,9 +678,10 @@ impl NodeInterner { name: Ident, local_id: LocalModuleId, file: FileId, + attributes: Vec, ) -> GlobalId { let statement = self.push_stmt(HirStatement::Error); - self.push_global(name, local_id, statement, file) + self.push_global(name, local_id, statement, file, attributes) } /// Intern an empty function. @@ -838,6 +844,10 @@ impl NodeInterner { &self.struct_attributes[struct_id] } + pub fn global_attributes(&self, global_id: &GlobalId) -> &[SecondaryAttribute] { + &self.global_attributes[global_id] + } + /// Returns the interned statement corresponding to `stmt_id` pub fn statement(&self, stmt_id: &StmtId) -> HirStatement { let def = @@ -1079,7 +1089,6 @@ impl NodeInterner { /// constraint, but when where clauses are involved, the failing constraint may be several /// constraints deep. In this case, all of the constraints are returned, starting with the /// failing one. - /// If this list of failing constraints is empty, this means type annotations are required. pub fn lookup_trait_implementation( &self, object_type: &Type, @@ -1122,10 +1131,6 @@ impl NodeInterner { } /// Similar to `lookup_trait_implementation` but does not apply any type bindings on success. - /// On error returns either: - /// - 1+ failing trait constraints, including the original. - /// Each constraint after the first represents a `where` clause that was followed. - /// - 0 trait constraints indicating type annotations are needed to choose an impl. pub fn try_lookup_trait_implementation( &self, object_type: &Type, @@ -1143,11 +1148,6 @@ impl NodeInterner { Ok((impl_kind, bindings)) } - /// Returns the trait implementation if found. - /// On error returns either: - /// - 1+ failing trait constraints, including the original. - /// Each constraint after the first represents a `where` clause that was followed. - /// - 0 trait constraints indicating type annotations are needed to choose an impl. fn lookup_trait_implementation_helper( &self, object_type: &Type, @@ -1166,22 +1166,15 @@ impl NodeInterner { let object_type = object_type.substitute(type_bindings); - // If the object type isn't known, just return an error saying type annotations are needed. - if object_type.is_bindable() { - return Err(Vec::new()); - } - let impls = self.trait_implementation_map.get(&trait_id).ok_or_else(|| vec![make_constraint()])?; - let mut matching_impls = Vec::new(); - for (existing_object_type2, impl_kind) in impls { // Bug: We're instantiating only the object type's generics here, not all of the trait's generics like we need to let (existing_object_type, instantiation_bindings) = existing_object_type2.instantiate(self); - let mut fresh_bindings = type_bindings.clone(); + let mut fresh_bindings = TypeBindings::new(); let mut check_trait_generics = |impl_generics: &[Type]| { trait_generics.iter().zip(impl_generics).all(|(trait_generic, impl_generic2)| { @@ -1206,13 +1199,16 @@ impl NodeInterner { } if object_type.try_unify(&existing_object_type, &mut fresh_bindings).is_ok() { + // The unification was successful so we can append fresh_bindings to our bindings list + type_bindings.extend(fresh_bindings); + if let TraitImplKind::Normal(impl_id) = impl_kind { let trait_impl = self.get_trait_implementation(*impl_id); let trait_impl = trait_impl.borrow(); if let Err(mut errors) = self.validate_where_clause( &trait_impl.where_clause, - &mut fresh_bindings, + type_bindings, &instantiation_bindings, recursion_limit, ) { @@ -1221,20 +1217,11 @@ impl NodeInterner { } } - matching_impls.push((impl_kind.clone(), fresh_bindings)); + return Ok(impl_kind.clone()); } } - if matching_impls.len() == 1 { - let (impl_, fresh_bindings) = matching_impls.pop().unwrap(); - *type_bindings = fresh_bindings; - Ok(impl_) - } else if matching_impls.is_empty() { - Err(vec![make_constraint()]) - } else { - // multiple matching impls, type annotations needed - Err(vec![]) - } + Err(vec![make_constraint()]) } /// Verifies that each constraint in the given where clause is valid. @@ -1250,11 +1237,12 @@ impl NodeInterner { // Instantiation bindings are generally safe to force substitute into the same type. // This is needed here to undo any bindings done to trait methods by monomorphization. // Otherwise, an impl for (A, B) could get narrowed to only an impl for e.g. (u8, u16). - let constraint_type = - constraint.typ.force_substitute(instantiation_bindings).substitute(type_bindings); + let constraint_type = constraint.typ.force_substitute(instantiation_bindings); + let constraint_type = constraint_type.substitute(type_bindings); let trait_generics = vecmap(&constraint.trait_generics, |generic| { - generic.force_substitute(instantiation_bindings).substitute(type_bindings) + let generic = generic.force_substitute(instantiation_bindings); + generic.substitute(type_bindings) }); self.lookup_trait_implementation_helper( @@ -1263,11 +1251,10 @@ impl NodeInterner { &trait_generics, // Use a fresh set of type bindings here since the constraint_type originates from // our impl list, which we don't want to bind to. - type_bindings, + &mut TypeBindings::new(), recursion_limit - 1, )?; } - Ok(()) } diff --git a/compiler/noirc_frontend/src/parser/parser.rs b/compiler/noirc_frontend/src/parser/parser.rs index 7ecff12163a..9712ba6c8c0 100644 --- a/compiler/noirc_frontend/src/parser/parser.rs +++ b/compiler/noirc_frontend/src/parser/parser.rs @@ -158,14 +158,17 @@ fn implementation() -> impl NoirParser { /// global_declaration: 'global' ident global_type_annotation '=' literal fn global_declaration() -> impl NoirParser { - let p = ignore_then_commit( - keyword(Keyword::Global).labelled(ParsingRuleLabel::Global), - ident().map(Pattern::Identifier), - ); + let p = attributes::attributes() + .then_ignore(keyword(Keyword::Global).labelled(ParsingRuleLabel::Global)) + .then(ident().map(Pattern::Identifier)); let p = then_commit(p, optional_type_annotation()); let p = then_commit_ignore(p, just(Token::Assign)); let p = then_commit(p, expression()); - p.map(LetStatement::new_let).map(TopLevelStatement::Global) + p.validate(|(((attributes, pattern), r#type), expression), span, emit| { + let global_attributes = attributes::validate_secondary_attributes(attributes, span, emit); + LetStatement { pattern, r#type, expression, attributes: global_attributes } + }) + .map(TopLevelStatement::Global) } /// submodule: 'mod' ident '{' module '}' @@ -526,8 +529,8 @@ fn assign_operator() -> impl NoirParser { } enum LValueRhs { - MemberAccess(Ident, Span), - Index(Expression, Span), + MemberAccess(Ident), + Index(Expression), } fn lvalue<'a, P>(expr_parser: P) -> impl NoirParser + 'a @@ -539,28 +542,23 @@ where let dereferences = just(Token::Star) .ignore_then(lvalue.clone()) - .map_with_span(|lvalue, span| LValue::Dereference(Box::new(lvalue), span)); + .map(|lvalue| LValue::Dereference(Box::new(lvalue))); let parenthesized = lvalue.delimited_by(just(Token::LeftParen), just(Token::RightParen)); let term = choice((parenthesized, dereferences, l_ident)); - let l_member_rhs = - just(Token::Dot).ignore_then(field_name()).map_with_span(LValueRhs::MemberAccess); + let l_member_rhs = just(Token::Dot).ignore_then(field_name()).map(LValueRhs::MemberAccess); let l_index = expr_parser .delimited_by(just(Token::LeftBracket), just(Token::RightBracket)) - .map_with_span(LValueRhs::Index); + .map(LValueRhs::Index); term.then(l_member_rhs.or(l_index).repeated()).foldl(|lvalue, rhs| match rhs { - LValueRhs::MemberAccess(field_name, span) => { - let span = lvalue.span().merge(span); - LValue::MemberAccess { object: Box::new(lvalue), field_name, span } - } - LValueRhs::Index(index, span) => { - let span = lvalue.span().merge(span); - LValue::Index { array: Box::new(lvalue), index, span } + LValueRhs::MemberAccess(field_name) => { + LValue::MemberAccess { object: Box::new(lvalue), field_name } } + LValueRhs::Index(index) => LValue::Index { array: Box::new(lvalue), index }, }) }) } diff --git a/compiler/noirc_frontend/src/parser/parser/attributes.rs b/compiler/noirc_frontend/src/parser/parser/attributes.rs index 4b256a95c8b..47add6f82e0 100644 --- a/compiler/noirc_frontend/src/parser/parser/attributes.rs +++ b/compiler/noirc_frontend/src/parser/parser/attributes.rs @@ -2,6 +2,7 @@ use chumsky::Parser; use noirc_errors::Span; use crate::{ + macros_api::SecondaryAttribute, parser::{NoirParser, ParserError, ParserErrorReason}, token::{Attribute, Attributes, Token, TokenKind}, }; @@ -44,3 +45,25 @@ pub(super) fn validate_attributes( Attributes { function: primary, secondary } } + +pub(super) fn validate_secondary_attributes( + attributes: Vec, + span: Span, + emit: &mut dyn FnMut(ParserError), +) -> Vec { + let mut struct_attributes = vec![]; + + for attribute in attributes { + match attribute { + Attribute::Function(..) => { + emit(ParserError::with_reason( + ParserErrorReason::NoFunctionAttributesAllowedOnStruct, + span, + )); + } + Attribute::Secondary(attr) => struct_attributes.push(attr), + } + } + + struct_attributes +} diff --git a/compiler/noirc_frontend/src/parser/parser/structs.rs b/compiler/noirc_frontend/src/parser/parser/structs.rs index 0212f56783f..87e58f69efb 100644 --- a/compiler/noirc_frontend/src/parser/parser/structs.rs +++ b/compiler/noirc_frontend/src/parser/parser/structs.rs @@ -1,17 +1,15 @@ use chumsky::prelude::*; -use noirc_errors::Span; use crate::{ - macros_api::SecondaryAttribute, parser::{ parser::{ - attributes::attributes, + attributes::{attributes, validate_secondary_attributes}, function, parse_type, primitives::{ident, keyword}, }, - NoirParser, ParserError, ParserErrorReason, TopLevelStatement, + NoirParser, TopLevelStatement, }, - token::{Attribute, Keyword, Token}, + token::{Keyword, Token}, Ident, NoirStruct, UnresolvedType, }; @@ -35,7 +33,7 @@ pub(super) fn struct_definition() -> impl NoirParser { .then(function::generics()) .then(fields) .validate(|(((raw_attributes, name), generics), fields), span, emit| { - let attributes = validate_struct_attributes(raw_attributes, span, emit); + let attributes = validate_secondary_attributes(raw_attributes, span, emit); TopLevelStatement::Struct(NoirStruct { name, attributes, generics, fields, span }) }) } @@ -48,28 +46,6 @@ fn struct_fields() -> impl NoirParser> { .allow_trailing() } -fn validate_struct_attributes( - attributes: Vec, - span: Span, - emit: &mut dyn FnMut(ParserError), -) -> Vec { - let mut struct_attributes = vec![]; - - for attribute in attributes { - match attribute { - Attribute::Function(..) => { - emit(ParserError::with_reason( - ParserErrorReason::NoFunctionAttributesAllowedOnStruct, - span, - )); - } - Attribute::Secondary(attr) => struct_attributes.push(attr), - } - } - - struct_attributes -} - #[cfg(test)] mod test { use super::*; diff --git a/compiler/noirc_frontend/src/tests.rs b/compiler/noirc_frontend/src/tests.rs index c4f0a8d67ba..6f92cb52a88 100644 --- a/compiler/noirc_frontend/src/tests.rs +++ b/compiler/noirc_frontend/src/tests.rs @@ -1033,19 +1033,19 @@ mod test { fn resolve_complex_closures() { let src = r#" fn main(x: Field) -> pub Field { - let closure_without_captures = |x: Field| -> Field { x + x }; + let closure_without_captures = |x| x + x; let a = closure_without_captures(1); - let closure_capturing_a_param = |y: Field| -> Field { y + x }; + let closure_capturing_a_param = |y| y + x; let b = closure_capturing_a_param(2); - let closure_capturing_a_local_var = |y: Field| -> Field { y + b }; + let closure_capturing_a_local_var = |y| y + b; let c = closure_capturing_a_local_var(3); - let closure_with_transitive_captures = |y: Field| -> Field { + let closure_with_transitive_captures = |y| { let d = 5; - let nested_closure = |z: Field| -> Field { - let doubly_nested_closure = |w: Field| -> Field { w + x + b }; + let nested_closure = |z| { + let doubly_nested_closure = |w| w + x + b; a + z + y + d + x + doubly_nested_closure(4) + x + y }; let res = nested_closure(5); diff --git a/compiler/wasm/src/compile.rs b/compiler/wasm/src/compile.rs index 9e6fca1126e..de157a1fe20 100644 --- a/compiler/wasm/src/compile.rs +++ b/compiler/wasm/src/compile.rs @@ -30,11 +30,16 @@ export type DependencyGraph = { library_dependencies: Readonly>; } +export type ContractOutputsArtifact = { + structs: Record>; + globals: Record>; +} + export type ContractArtifact = { noir_version: string; name: string; functions: Array; - events: Array; + outputs: ContractOutputsArtifact; file_map: Record; }; @@ -218,7 +223,7 @@ pub fn compile_contract( noir_version: String::from(NOIR_ARTIFACT_VERSION_STRING), name: optimized_contract.name, functions, - events: optimized_contract.events, + outputs: optimized_contract.outputs.into(), file_map: optimized_contract.file_map, }; diff --git a/compiler/wasm/src/compile_new.rs b/compiler/wasm/src/compile_new.rs index d6b382f669f..c187fe7f3de 100644 --- a/compiler/wasm/src/compile_new.rs +++ b/compiler/wasm/src/compile_new.rs @@ -146,7 +146,7 @@ impl CompilerContext { noir_version: String::from(NOIR_ARTIFACT_VERSION_STRING), name: optimized_contract.name, functions, - events: optimized_contract.events, + outputs: optimized_contract.outputs.into(), file_map: optimized_contract.file_map, }; diff --git a/compiler/wasm/src/types/noir_artifact.ts b/compiler/wasm/src/types/noir_artifact.ts index 935c99043da..f241b539dc7 100644 --- a/compiler/wasm/src/types/noir_artifact.ts +++ b/compiler/wasm/src/types/noir_artifact.ts @@ -1,35 +1,55 @@ import { Abi, AbiType } from '@noir-lang/types'; /** - * A named type. + * A basic value. */ -export interface ABIVariable { +export interface BasicValue { /** - * The name of the variable. - */ - name: string; - /** - * The type of the variable. + * The kind of the value. */ - type: AbiType; + kind: T; + value: V; } /** - * A contract event. + * An exported value. */ -export interface EventAbi { +export type AbiValue = + | BasicValue<'boolean', boolean> + | BasicValue<'string', string> + | BasicValue<'array', AbiValue[]> + | TupleValue + | IntegerValue + | StructValue; + +export type TypedStructFieldValue = { name: string; value: T }; + +export interface StructValue { + kind: 'struct'; + fields: TypedStructFieldValue[]; +} + +export interface TupleValue { + kind: 'tuple'; + fields: AbiValue[]; +} + +export interface IntegerValue extends BasicValue<'integer', string> { + sign: boolean; +} + +/** + * A named type. + */ +export interface ABIVariable { /** - * The event name. + * The name of the variable. */ name: string; /** - * Fully qualified name of the event. - */ - path: string; - /** - * The fields of the event. + * The type of the variable. */ - fields: ABIVariable[]; + type: AbiType; } /** @@ -60,8 +80,11 @@ export interface ContractArtifact { noir_version: string; /** The functions of the contract. */ functions: NoirFunctionEntry[]; - /** The events of the contract */ - events: EventAbi[]; + + outputs: { + structs: Record; + globals: Record; + }; /** The map of file ID to the source code and path of the file. */ file_map: DebugFileMap; } diff --git a/cspell.json b/cspell.json index 16de9757fb8..8cfc5e695a2 100644 --- a/cspell.json +++ b/cspell.json @@ -6,7 +6,6 @@ "words": [ "aarch", "acir", - "acirs", "acvm", "aeiou", "appender", @@ -37,7 +36,6 @@ "castable", "catmcgee", "Celo", - "chrono", "chumsky", "codegen", "codegenned", diff --git a/noir_stdlib/src/cmp.nr b/noir_stdlib/src/cmp.nr index dde29d7ee87..0eed50eb42b 100644 --- a/noir_stdlib/src/cmp.nr +++ b/noir_stdlib/src/cmp.nr @@ -6,10 +6,10 @@ trait Eq { impl Eq for Field { fn eq(self, other: Field) -> bool { self == other } } -impl Eq for u64 { fn eq(self, other: u64) -> bool { self == other } } -impl Eq for u32 { fn eq(self, other: u32) -> bool { self == other } } -impl Eq for u8 { fn eq(self, other: u8) -> bool { self == other } } impl Eq for u1 { fn eq(self, other: u1) -> bool { self == other } } +impl Eq for u8 { fn eq(self, other: u8) -> bool { self == other } } +impl Eq for u32 { fn eq(self, other: u32) -> bool { self == other } } +impl Eq for u64 { fn eq(self, other: u64) -> bool { self == other } } impl Eq for i8 { fn eq(self, other: i8) -> bool { self == other } } impl Eq for i32 { fn eq(self, other: i32) -> bool { self == other } } @@ -107,8 +107,8 @@ trait Ord { // Note: Field deliberately does not implement Ord -impl Ord for u64 { - fn cmp(self, other: u64) -> Ordering { +impl Ord for u8 { + fn cmp(self, other: u8) -> Ordering { if self < other { Ordering::less() } else if self > other { @@ -131,8 +131,8 @@ impl Ord for u32 { } } -impl Ord for u8 { - fn cmp(self, other: u8) -> Ordering { +impl Ord for u64 { + fn cmp(self, other: u64) -> Ordering { if self < other { Ordering::less() } else if self > other { diff --git a/noir_stdlib/src/hash/poseidon2.nr b/noir_stdlib/src/hash/poseidon2.nr index 12bf373e671..5b97d809896 100644 --- a/noir_stdlib/src/hash/poseidon2.nr +++ b/noir_stdlib/src/hash/poseidon2.nr @@ -1,7 +1,7 @@ use crate::hash::Hasher; use crate::default::Default; -global RATE: u32 = 3; +global RATE = 3; struct Poseidon2 { cache: [Field;3], diff --git a/noir_stdlib/src/ops.nr b/noir_stdlib/src/ops.nr index d855e794fb4..e561265629e 100644 --- a/noir_stdlib/src/ops.nr +++ b/noir_stdlib/src/ops.nr @@ -6,9 +6,9 @@ trait Add { impl Add for Field { fn add(self, other: Field) -> Field { self + other } } -impl Add for u64 { fn add(self, other: u64) -> u64 { self + other } } -impl Add for u32 { fn add(self, other: u32) -> u32 { self + other } } impl Add for u8 { fn add(self, other: u8) -> u8 { self + other } } +impl Add for u32 { fn add(self, other: u32) -> u32 { self + other } } +impl Add for u64 { fn add(self, other: u64) -> u64 { self + other } } impl Add for i8 { fn add(self, other: i8) -> i8 { self + other } } impl Add for i32 { fn add(self, other: i32) -> i32 { self + other } } @@ -22,9 +22,9 @@ trait Sub { impl Sub for Field { fn sub(self, other: Field) -> Field { self - other } } -impl Sub for u64 { fn sub(self, other: u64) -> u64 { self - other } } -impl Sub for u32 { fn sub(self, other: u32) -> u32 { self - other } } impl Sub for u8 { fn sub(self, other: u8) -> u8 { self - other } } +impl Sub for u32 { fn sub(self, other: u32) -> u32 { self - other } } +impl Sub for u64 { fn sub(self, other: u64) -> u64 { self - other } } impl Sub for i8 { fn sub(self, other: i8) -> i8 { self - other } } impl Sub for i32 { fn sub(self, other: i32) -> i32 { self - other } } @@ -38,9 +38,9 @@ trait Mul { impl Mul for Field { fn mul(self, other: Field) -> Field { self * other } } -impl Mul for u64 { fn mul(self, other: u64) -> u64 { self * other } } -impl Mul for u32 { fn mul(self, other: u32) -> u32 { self * other } } impl Mul for u8 { fn mul(self, other: u8) -> u8 { self * other } } +impl Mul for u32 { fn mul(self, other: u32) -> u32 { self * other } } +impl Mul for u64 { fn mul(self, other: u64) -> u64 { self * other } } impl Mul for i8 { fn mul(self, other: i8) -> i8 { self * other } } impl Mul for i32 { fn mul(self, other: i32) -> i32 { self * other } } @@ -54,9 +54,9 @@ trait Div { impl Div for Field { fn div(self, other: Field) -> Field { self / other } } -impl Div for u64 { fn div(self, other: u64) -> u64 { self / other } } -impl Div for u32 { fn div(self, other: u32) -> u32 { self / other } } impl Div for u8 { fn div(self, other: u8) -> u8 { self / other } } +impl Div for u32 { fn div(self, other: u32) -> u32 { self / other } } +impl Div for u64 { fn div(self, other: u64) -> u64 { self / other } } impl Div for i8 { fn div(self, other: i8) -> i8 { self / other } } impl Div for i32 { fn div(self, other: i32) -> i32 { self / other } } @@ -68,9 +68,9 @@ trait Rem{ } // docs:end:rem-trait -impl Rem for u64 { fn rem(self, other: u64) -> u64 { self % other } } -impl Rem for u32 { fn rem(self, other: u32) -> u32 { self % other } } impl Rem for u8 { fn rem(self, other: u8) -> u8 { self % other } } +impl Rem for u32 { fn rem(self, other: u32) -> u32 { self % other } } +impl Rem for u64 { fn rem(self, other: u64) -> u64 { self % other } } impl Rem for i8 { fn rem(self, other: i8) -> i8 { self % other } } impl Rem for i32 { fn rem(self, other: i32) -> i32 { self % other } } @@ -84,9 +84,9 @@ trait BitOr { impl BitOr for bool { fn bitor(self, other: bool) -> bool { self | other } } -impl BitOr for u64 { fn bitor(self, other: u64) -> u64 { self | other } } -impl BitOr for u32 { fn bitor(self, other: u32) -> u32 { self | other } } impl BitOr for u8 { fn bitor(self, other: u8) -> u8 { self | other } } +impl BitOr for u32 { fn bitor(self, other: u32) -> u32 { self | other } } +impl BitOr for u64 { fn bitor(self, other: u64) -> u64 { self | other } } impl BitOr for i8 { fn bitor(self, other: i8) -> i8 { self | other } } impl BitOr for i32 { fn bitor(self, other: i32) -> i32 { self | other } } @@ -100,9 +100,9 @@ trait BitAnd { impl BitAnd for bool { fn bitand(self, other: bool) -> bool { self & other } } -impl BitAnd for u64 { fn bitand(self, other: u64) -> u64 { self & other } } -impl BitAnd for u32 { fn bitand(self, other: u32) -> u32 { self & other } } impl BitAnd for u8 { fn bitand(self, other: u8) -> u8 { self & other } } +impl BitAnd for u32 { fn bitand(self, other: u32) -> u32 { self & other } } +impl BitAnd for u64 { fn bitand(self, other: u64) -> u64 { self & other } } impl BitAnd for i8 { fn bitand(self, other: i8) -> i8 { self & other } } impl BitAnd for i32 { fn bitand(self, other: i32) -> i32 { self & other } } @@ -116,9 +116,9 @@ trait BitXor { impl BitXor for bool { fn bitxor(self, other: bool) -> bool { self ^ other } } -impl BitXor for u64 { fn bitxor(self, other: u64) -> u64 { self ^ other } } -impl BitXor for u32 { fn bitxor(self, other: u32) -> u32 { self ^ other } } impl BitXor for u8 { fn bitxor(self, other: u8) -> u8 { self ^ other } } +impl BitXor for u32 { fn bitxor(self, other: u32) -> u32 { self ^ other } } +impl BitXor for u64 { fn bitxor(self, other: u64) -> u64 { self ^ other } } impl BitXor for i8 { fn bitxor(self, other: i8) -> i8 { self ^ other } } impl BitXor for i32 { fn bitxor(self, other: i32) -> i32 { self ^ other } } @@ -130,14 +130,14 @@ trait Shl { } // docs:end:shl-trait +impl Shl for u8 { fn shl(self, other: u8) -> u8 { self << other } } impl Shl for u32 { fn shl(self, other: u32) -> u32 { self << other } } impl Shl for u64 { fn shl(self, other: u64) -> u64 { self << other } } -impl Shl for u8 { fn shl(self, other: u8) -> u8 { self << other } } -impl Shl for u1 { fn shl(self, other: u1) -> u1 { self << other } } -impl Shl for i8 { fn shl(self, other: i8) -> i8 { self << other } } -impl Shl for i32 { fn shl(self, other: i32) -> i32 { self << other } } -impl Shl for i64 { fn shl(self, other: i64) -> i64 { self << other } } +// Bit shifting is not currently supported for signed integer types +// impl Shl for i8 { fn shl(self, other: i8) -> i8 { self << other } } +// impl Shl for i32 { fn shl(self, other: i32) -> i32 { self << other } } +// impl Shl for i64 { fn shl(self, other: i64) -> i64 { self << other } } // docs:start:shr-trait trait Shr { @@ -145,11 +145,11 @@ trait Shr { } // docs:end:shr-trait -impl Shr for u64 { fn shr(self, other: u64) -> u64 { self >> other } } -impl Shr for u32 { fn shr(self, other: u32) -> u32 { self >> other } } impl Shr for u8 { fn shr(self, other: u8) -> u8 { self >> other } } -impl Shr for u1 { fn shr(self, other: u1) -> u1 { self >> other } } +impl Shr for u32 { fn shr(self, other: u32) -> u32 { self >> other } } +impl Shr for u64 { fn shr(self, other: u64) -> u64 { self >> other } } -impl Shr for i8 { fn shr(self, other: i8) -> i8 { self >> other } } -impl Shr for i32 { fn shr(self, other: i32) -> i32 { self >> other } } -impl Shr for i64 { fn shr(self, other: i64) -> i64 { self >> other } } +// Bit shifting is not currently supported for signed integer types +// impl Shr for i8 { fn shr(self, other: i8) -> i8 { self >> other } } +// impl Shr for i32 { fn shr(self, other: i32) -> i32 { self >> other } } +// impl Shr for i64 { fn shr(self, other: i64) -> i64 { self >> other } } diff --git a/test_programs/compile_failure/array_length_defaulting/Nargo.toml b/test_programs/compile_failure/array_length_defaulting/Nargo.toml deleted file mode 100644 index fa376596ee2..00000000000 --- a/test_programs/compile_failure/array_length_defaulting/Nargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "array_length_defaulting" -type = "bin" -authors = [""] -compiler_version = ">=0.26.0" - -[dependencies] diff --git a/test_programs/compile_failure/array_length_defaulting/src/main.nr b/test_programs/compile_failure/array_length_defaulting/src/main.nr deleted file mode 100644 index 216a9ae3f0c..00000000000 --- a/test_programs/compile_failure/array_length_defaulting/src/main.nr +++ /dev/null @@ -1,10 +0,0 @@ -fn main() { - let x = dep::std::unsafe::zeroed(); - foo(x); -} - -fn foo(array: [Field; N]) { - for elem in array { - println(elem); - } -} diff --git a/test_programs/execution_failure/hashmap_load_factor/Nargo.toml b/test_programs/compile_failure/hashmap_load_factor/Nargo.toml similarity index 100% rename from test_programs/execution_failure/hashmap_load_factor/Nargo.toml rename to test_programs/compile_failure/hashmap_load_factor/Nargo.toml diff --git a/test_programs/execution_failure/hashmap_load_factor/src/main.nr b/test_programs/compile_failure/hashmap_load_factor/src/main.nr similarity index 100% rename from test_programs/execution_failure/hashmap_load_factor/src/main.nr rename to test_programs/compile_failure/hashmap_load_factor/src/main.nr diff --git a/test_programs/compile_failure/typevar_default/Nargo.toml b/test_programs/compile_failure/typevar_default/Nargo.toml deleted file mode 100644 index b3cd08bb8fe..00000000000 --- a/test_programs/compile_failure/typevar_default/Nargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "typevar_default" -type = "bin" -authors = [""] -compiler_version = ">=0.26.0" - -[dependencies] \ No newline at end of file diff --git a/test_programs/compile_failure/typevar_default/src/main.nr b/test_programs/compile_failure/typevar_default/src/main.nr deleted file mode 100644 index 1eb9cf63de3..00000000000 --- a/test_programs/compile_failure/typevar_default/src/main.nr +++ /dev/null @@ -1,12 +0,0 @@ -fn main() { - // Expecting error: type annotations needed (N not known) - let _ = slice_to_array(&[1, 2, 3]); -} - -fn slice_to_array(slice: [Field]) -> [Field; N] { - let mut array = [0; N]; - for i in 0 .. N { - array[i] = slice[i]; - } - array -} diff --git a/test_programs/compile_success_empty/option/src/main.nr b/test_programs/compile_success_empty/option/src/main.nr index c5f321256b1..989c8f65bf4 100644 --- a/test_programs/compile_success_empty/option/src/main.nr +++ b/test_programs/compile_success_empty/option/src/main.nr @@ -39,9 +39,9 @@ fn main() { let add1_u64 = |value: Field| Option::some(value as u64 + 1); - assert(none.and_then(|_value| none).is_none()); + assert(none.and_then(|_value| Option::none()).is_none()); assert(none.and_then(add1_u64).is_none()); - assert(some.and_then(|_value| none).is_none()); + assert(some.and_then(|_value| Option::none()).is_none()); assert(some.and_then(add1_u64).unwrap() == 4); assert(some.and_then(|x| Option::some(x + ten)).unwrap() == 13); diff --git a/test_programs/compile_success_empty/regression_4635/Nargo.toml b/test_programs/compile_success_empty/regression_4635/Nargo.toml deleted file mode 100644 index 563e262410f..00000000000 --- a/test_programs/compile_success_empty/regression_4635/Nargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "regression_4635" -type = "bin" -authors = [""] -compiler_version = ">=0.26.0" - -[dependencies] diff --git a/test_programs/compile_success_empty/regression_4635/src/main.nr b/test_programs/compile_success_empty/regression_4635/src/main.nr deleted file mode 100644 index 23918e30785..00000000000 --- a/test_programs/compile_success_empty/regression_4635/src/main.nr +++ /dev/null @@ -1,59 +0,0 @@ -trait FromField { - fn from_field(field: Field) -> Self; -} - -impl FromField for Field { - fn from_field(value: Field) -> Self { - value - } -} - -trait Deserialize { - fn deserialize(fields: [Field; N]) -> Self; -} - -global AZTEC_ADDRESS_LENGTH = 1; - -struct AztecAddress { - inner : Field -} - -impl FromField for AztecAddress { - fn from_field(value: Field) -> Self { - Self { inner: value } - } -} - -impl Deserialize for AztecAddress { - fn deserialize(fields: [Field; AZTEC_ADDRESS_LENGTH]) -> Self { - AztecAddress::from_field(fields[0]) - } -} - -impl Eq for AztecAddress { - fn eq(self, other: Self) -> bool { - self.inner == other.inner - } -} - -// Custom code - -struct MyStruct { - a: T -} - -impl Deserialize<1> for MyStruct { - fn deserialize(fields: [Field; 1]) -> Self where T: FromField { - Self{ a: FromField::from_field(fields[0]) } - } -} - -fn main() { - let fields = [5; 1]; - let foo = MyStruct::deserialize(fields); // Note I don't specify T here (the type of `foo.a`) - - let bar = AztecAddress { inner: 5 }; - - // Here `T` is apparently inferred to be `AztecAddress`, presumably because of the comparison. - assert(foo.a == bar); -} diff --git a/test_programs/execution_failure/hashmap_load_factor/Prover.toml b/test_programs/execution_failure/hashmap_load_factor/Prover.toml deleted file mode 100644 index 6d72cab47fa..00000000000 --- a/test_programs/execution_failure/hashmap_load_factor/Prover.toml +++ /dev/null @@ -1,23 +0,0 @@ -[[input]] -key = 1 -value = 0 - -[[input]] -key = 2 -value = 0 - -[[input]] -key = 3 -value = 0 - -[[input]] -key = 4 -value = 0 - -[[input]] -key = 5 -value = 0 - -[[input]] -key = 6 -value = 0 diff --git a/test_programs/execution_success/bit_shifts_runtime/src/main.nr b/test_programs/execution_success/bit_shifts_runtime/src/main.nr index ff424c9fbf6..28b3ef656c1 100644 --- a/test_programs/execution_success/bit_shifts_runtime/src/main.nr +++ b/test_programs/execution_success/bit_shifts_runtime/src/main.nr @@ -7,7 +7,7 @@ fn main(x: u64, y: u64) { assert(x >> y == 32); // Bit-shift with signed integers - let mut a: i8 = y as i8; + let mut a :i8 = y as i8; let mut b: i8 = x as i8; assert(b << 1 == -128); assert(b >> 2 == 16); diff --git a/test_programs/execution_success/fold_basic_nested_call/src/main.nr b/test_programs/execution_success/fold_basic_nested_call/src/main.nr index 6d02b734727..3eb16b409ff 100644 --- a/test_programs/execution_success/fold_basic_nested_call/src/main.nr +++ b/test_programs/execution_success/fold_basic_nested_call/src/main.nr @@ -13,4 +13,4 @@ fn func_with_nested_foo_call(x: Field, y: Field) -> Field { fn foo(x: Field, y: Field) -> Field { assert(x != y); x -} +} \ No newline at end of file diff --git a/test_programs/execution_success/prelude/src/main.nr b/test_programs/execution_success/prelude/src/main.nr index 226341f1e7b..c9ae448c486 100644 --- a/test_programs/execution_success/prelude/src/main.nr +++ b/test_programs/execution_success/prelude/src/main.nr @@ -1,6 +1,6 @@ fn main() { - let _xs: Vec = Vec::new(); - let _option: Option = Option::none(); + let _xs = Vec::new(); + let _option = Option::none(); print("42\n"); println("42"); diff --git a/test_programs/execution_success/regression_sha256_slice/Nargo.toml b/test_programs/execution_success/regression_sha256_slice/Nargo.toml deleted file mode 100644 index 759c3b20ba8..00000000000 --- a/test_programs/execution_success/regression_sha256_slice/Nargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "regression_sha256_slice" -type = "bin" -authors = [""] -compiler_version = ">=0.26.0" - -[dependencies] \ No newline at end of file diff --git a/test_programs/execution_success/regression_sha256_slice/Prover.toml b/test_programs/execution_success/regression_sha256_slice/Prover.toml deleted file mode 100644 index 8a027e9eca9..00000000000 --- a/test_programs/execution_success/regression_sha256_slice/Prover.toml +++ /dev/null @@ -1 +0,0 @@ -x = ["5", "10"] diff --git a/test_programs/execution_success/regression_sha256_slice/src/main.nr b/test_programs/execution_success/regression_sha256_slice/src/main.nr deleted file mode 100644 index 60b0911cf09..00000000000 --- a/test_programs/execution_success/regression_sha256_slice/src/main.nr +++ /dev/null @@ -1,12 +0,0 @@ -use dep::std; - -fn main(x: [u8; 2]) { - let mut y = x.as_slice(); - let digest1 = std::hash::sha256_slice(y); - let mut v = y; - if x[0] != 0 { - v = y.push_back(x[0]); - } - let digest2 = std::hash::sha256_slice(v); - assert(digest1 != digest2); -} diff --git a/tooling/bb_abstraction_leaks/build.rs b/tooling/bb_abstraction_leaks/build.rs index 52f7783851a..362d2132952 100644 --- a/tooling/bb_abstraction_leaks/build.rs +++ b/tooling/bb_abstraction_leaks/build.rs @@ -10,7 +10,7 @@ use const_format::formatcp; const USERNAME: &str = "AztecProtocol"; const REPO: &str = "aztec-packages"; -const VERSION: &str = "0.32.0"; +const VERSION: &str = "0.30.1"; const TAG: &str = formatcp!("aztec-packages-v{}", VERSION); const API_URL: &str = diff --git a/tooling/debugger/ignored-tests.txt b/tooling/debugger/ignored-tests.txt index 5a42ef36e7e..854e284dd43 100644 --- a/tooling/debugger/ignored-tests.txt +++ b/tooling/debugger/ignored-tests.txt @@ -12,5 +12,3 @@ references scalar_mul signed_comparison to_bytes_integration -fold_basic -fold_basic_nested_call diff --git a/tooling/nargo/src/artifacts/contract.rs b/tooling/nargo/src/artifacts/contract.rs index c0316a6d1a2..868fb4404fd 100644 --- a/tooling/nargo/src/artifacts/contract.rs +++ b/tooling/nargo/src/artifacts/contract.rs @@ -1,14 +1,26 @@ use acvm::acir::circuit::Program; -use noirc_abi::{Abi, ContractEvent}; -use noirc_driver::{CompiledContract, ContractFunction}; +use noirc_abi::{Abi, AbiType, AbiValue}; +use noirc_driver::{CompiledContract, CompiledContractOutputs, ContractFunction}; use serde::{Deserialize, Serialize}; use noirc_driver::DebugFile; use noirc_errors::debug_info::DebugInfo; -use std::collections::BTreeMap; +use std::collections::{BTreeMap, HashMap}; use fm::FileId; +#[derive(Serialize, Deserialize)] +pub struct ContractOutputsArtifact { + pub structs: HashMap>, + pub globals: HashMap>, +} + +impl From for ContractOutputsArtifact { + fn from(outputs: CompiledContractOutputs) -> Self { + ContractOutputsArtifact { structs: outputs.structs, globals: outputs.globals } + } +} + #[derive(Serialize, Deserialize)] pub struct ContractArtifact { /// Version of noir used to compile this contract @@ -17,8 +29,8 @@ pub struct ContractArtifact { pub name: String, /// Each of the contract's functions are compiled into a separate program stored in this `Vec`. pub functions: Vec, - /// All the events defined inside the contract scope. - pub events: Vec, + + pub outputs: ContractOutputsArtifact, /// Map of file Id to the source code so locations in debug info can be mapped to source code they point to. pub file_map: BTreeMap, } @@ -29,7 +41,7 @@ impl From for ContractArtifact { noir_version: contract.noir_version, name: contract.name, functions: contract.functions.into_iter().map(ContractFunctionArtifact::from).collect(), - events: contract.events, + outputs: contract.outputs.into(), file_map: contract.file_map, } } diff --git a/tooling/nargo_cli/src/main.rs b/tooling/nargo_cli/src/main.rs index 6e2b7069bc4..3f797b0bf0c 100644 --- a/tooling/nargo_cli/src/main.rs +++ b/tooling/nargo_cli/src/main.rs @@ -25,14 +25,14 @@ fn main() { if let Ok(log_dir) = env::var("NARGO_LOG_DIR") { let debug_file = rolling::daily(log_dir, "nargo-log"); tracing_subscriber::fmt() - .with_span_events(FmtSpan::ENTER | FmtSpan::CLOSE) + .with_span_events(FmtSpan::ACTIVE) .with_writer(debug_file) .with_ansi(false) .with_env_filter(EnvFilter::from_default_env()) .init(); } else { tracing_subscriber::fmt() - .with_span_events(FmtSpan::ENTER | FmtSpan::CLOSE) + .with_span_events(FmtSpan::ACTIVE) .with_ansi(true) .with_env_filter(EnvFilter::from_env("NOIR_LOG")) .init(); diff --git a/tooling/noir_js_backend_barretenberg/package.json b/tooling/noir_js_backend_barretenberg/package.json index 251dd80c2f4..1ea384cdd49 100644 --- a/tooling/noir_js_backend_barretenberg/package.json +++ b/tooling/noir_js_backend_barretenberg/package.json @@ -42,7 +42,7 @@ "lint": "NODE_NO_WARNINGS=1 eslint . --ext .ts --ignore-path ./.eslintignore --max-warnings 0" }, "dependencies": { - "@aztec/bb.js": "0.32.0", + "@aztec/bb.js": "portal:../../../../barretenberg/ts", "@noir-lang/types": "workspace:*", "fflate": "^0.8.0" }, diff --git a/tooling/noirc_abi/src/lib.rs b/tooling/noirc_abi/src/lib.rs index d0dcb373963..8a385d581af 100644 --- a/tooling/noirc_abi/src/lib.rs +++ b/tooling/noirc_abi/src/lib.rs @@ -10,9 +10,7 @@ use acvm::{ use errors::AbiError; use input_parser::InputValue; use iter_extended::{try_btree_map, try_vecmap, vecmap}; -use noirc_frontend::{ - hir::Context, Signedness, StructType, Type, TypeBinding, TypeVariableKind, Visibility, -}; +use noirc_frontend::{hir::Context, Signedness, Type, TypeBinding, TypeVariableKind, Visibility}; use serde::{Deserialize, Serialize}; use std::ops::Range; use std::{collections::BTreeMap, str}; @@ -147,9 +145,7 @@ impl AbiType { Type::TypeVariable(binding, TypeVariableKind::IntegerOrField) | Type::TypeVariable(binding, TypeVariableKind::Integer) => match &*binding.borrow() { TypeBinding::Bound(typ) => Self::from_type(context, typ), - TypeBinding::Unbound(_) => { - Self::from_type(context, &Type::default_int_or_field_type()) - } + TypeBinding::Unbound(_) => Self::from_type(context, &Type::default_int_type()), }, Type::Bool => Self::Boolean, Type::String(size) => { @@ -515,31 +511,35 @@ fn decode_string_value(field_elements: &[FieldElement]) -> String { final_string.to_owned() } -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct ContractEvent { - /// Event name - name: String, - /// The fully qualified path to the event definition - path: String, - - /// Fields of the event - #[serde( - serialize_with = "serialization::serialize_struct_fields", - deserialize_with = "serialization::deserialize_struct_fields" - )] - fields: Vec<(String, AbiType)>, -} - -impl ContractEvent { - pub fn from_struct_type(context: &Context, struct_type: &StructType) -> Self { - let fields = vecmap(struct_type.get_fields(&[]), |(name, typ)| { - (name, AbiType::from_type(context, &typ)) - }); - // For the ABI, we always want to resolve the struct paths from the root crate - let path = context.fully_qualified_struct_path(context.root_crate_id(), struct_type.id); - - Self { name: struct_type.name.0.contents.clone(), path, fields } - } +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(tag = "kind", rename_all = "lowercase")] +pub enum AbiValue { + Field { + value: FieldElement, + }, + Integer { + sign: bool, + value: String, + }, + Boolean { + value: bool, + }, + String { + value: String, + }, + Array { + value: Vec, + }, + Struct { + #[serde( + serialize_with = "serialization::serialize_struct_field_values", + deserialize_with = "serialization::deserialize_struct_field_values" + )] + fields: Vec<(String, AbiValue)>, + }, + Tuple { + fields: Vec, + }, } fn range_to_vec(ranges: &[Range]) -> Vec { diff --git a/tooling/noirc_abi/src/serialization.rs b/tooling/noirc_abi/src/serialization.rs index ed838803fab..4f91d9b7dfd 100644 --- a/tooling/noirc_abi/src/serialization.rs +++ b/tooling/noirc_abi/src/serialization.rs @@ -1,8 +1,7 @@ +use crate::{AbiType, AbiValue}; use iter_extended::vecmap; use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use crate::AbiType; - // This module exposes a custom serializer and deserializer for `BTreeMap` // (representing the fields of a struct) to serialize it as a `Vec`. // @@ -41,6 +40,37 @@ where Ok(vecmap(fields_vector, |StructField { name, typ }| (name, typ))) } +#[derive(Serialize, Deserialize)] +struct StructFieldValue { + name: String, + value: AbiValue, +} + +pub(crate) fn serialize_struct_field_values( + fields: &[(String, AbiValue)], + s: S, +) -> Result +where + S: Serializer, +{ + let fields_vector = vecmap(fields, |(name, value)| StructFieldValue { + name: name.to_owned(), + value: value.to_owned(), + }); + + fields_vector.serialize(s) +} + +pub(crate) fn deserialize_struct_field_values<'de, D>( + deserializer: D, +) -> Result, D::Error> +where + D: Deserializer<'de>, +{ + let fields_vector = Vec::::deserialize(deserializer)?; + Ok(vecmap(fields_vector, |StructFieldValue { name, value }| (name, value))) +} + #[cfg(test)] mod tests { use crate::{AbiParameter, AbiType, AbiVisibility, Sign}; diff --git a/yarn.lock b/yarn.lock index a39ae9921da..b45678f5d8b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -221,19 +221,18 @@ __metadata: languageName: node linkType: hard -"@aztec/bb.js@npm:0.32.0": - version: 0.32.0 - resolution: "@aztec/bb.js@npm:0.32.0" +"@aztec/bb.js@portal:../../../../barretenberg/ts::locator=%40noir-lang%2Fbackend_barretenberg%40workspace%3Atooling%2Fnoir_js_backend_barretenberg": + version: 0.0.0-use.local + resolution: "@aztec/bb.js@portal:../../../../barretenberg/ts::locator=%40noir-lang%2Fbackend_barretenberg%40workspace%3Atooling%2Fnoir_js_backend_barretenberg" dependencies: comlink: ^4.4.1 commander: ^10.0.1 debug: ^4.3.4 tslib: ^2.4.0 bin: - bb.js: dest/node/main.js - checksum: 0919957e141ae0a65cfab961dce122fa06de628a10b7cb661d31d8ed4793ce80980fcf315620ceffffa45581db941bad43c392f4b2aa9becaaf7d2faaba01ffc + 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 @@ -4396,7 +4395,7 @@ __metadata: version: 0.0.0-use.local resolution: "@noir-lang/backend_barretenberg@workspace:tooling/noir_js_backend_barretenberg" dependencies: - "@aztec/bb.js": 0.32.0 + "@aztec/bb.js": "portal:../../../../barretenberg/ts" "@noir-lang/types": "workspace:*" "@types/node": ^20.6.2 "@types/prettier": ^3