From b366be4932f447103afe905be930ffa6bf294d45 Mon Sep 17 00:00:00 2001 From: Aztec Bot <49558828+AztecBot@users.noreply.github.com> Date: Wed, 24 Apr 2024 15:25:48 +0100 Subject: [PATCH] feat: Sync from noir (#5999) Automated pull of development from the [noir](https://github.com/noir-lang/noir) programming language, a dependency of Aztec. BEGIN_COMMIT_OVERRIDE fix: fix curve parameters for bigints (https://github.com/noir-lang/noir/pull/4900) chore: bump `rustls` to v0.21.11 (https://github.com/noir-lang/noir/pull/4895) fix: Update noir-gates-diff commit to use master reference report (https://github.com/noir-lang/noir/pull/4891) fix: Reset the noir-gates-diff report on master (https://github.com/noir-lang/noir/pull/4878) fix(experimental): Skip over comptime functions in scan pass (https://github.com/noir-lang/noir/pull/4893) chore(experimental): Improve variable not defined error message in comptime interpreter (https://github.com/noir-lang/noir/pull/4889) chore(experimental): Add scan pass and `into_expression` for comptime interpreter (https://github.com/noir-lang/noir/pull/4884) END_COMMIT_OVERRIDE --------- Co-authored-by: Tom French --- .noir-sync-commit | 2 +- .../actions/install-playwright/action.yml | 5 +- .../.github/workflows/gates_report.yml | 4 +- .../.github/workflows/test-js-packages.yml | 2 +- noir/noir-repo/Cargo.lock | 56 +++-- noir/noir-repo/acvm-repo/acvm_js/build.sh | 3 + .../aztec_macros/src/utils/hir_utils.rs | 9 +- .../noirc_frontend/src/ast/expression.rs | 2 + .../noirc_frontend/src/hir/comptime/errors.rs | 53 +++++ .../src/hir/comptime/hir_to_ast.rs | 22 +- .../src/hir/comptime/interpreter.rs | 176 ++++----------- .../noirc_frontend/src/hir/comptime/mod.rs | 5 + .../noirc_frontend/src/hir/comptime/scan.rs | 213 ++++++++++++++++++ .../noirc_frontend/src/hir/comptime/tests.rs | 4 +- .../noirc_frontend/src/hir/comptime/value.rs | 169 ++++++++++++++ .../src/hir/def_collector/dc_crate.rs | 162 +++++++------ .../src/hir/resolution/globals.rs | 8 +- .../src/hir/resolution/resolver.rs | 15 +- .../noirc_frontend/src/hir/type_check/expr.rs | 65 +++--- .../noirc_frontend/src/hir_def/expr.rs | 4 +- .../noirc_frontend/src/lexer/token.rs | 6 +- .../src/monomorphization/mod.rs | 6 + .../noirc_frontend/src/node_interner.rs | 10 +- .../noirc_frontend/src/noir_parser.lalrpop | 2 +- .../noirc_frontend/src/parser/parser.rs | 6 +- .../noirc_frontend/src/parser/parser/types.rs | 2 +- noir/noir-repo/noir_stdlib/src/bigint.nr | 86 ++++--- .../execution_success/bigint/src/main.nr | 20 +- .../tooling/nargo_cli/src/cli/info_cmd.rs | 6 +- .../tooling/nargo_fmt/src/rewrite/expr.rs | 3 + .../noir-repo/tooling/noirc_abi_wasm/build.sh | 1 + 31 files changed, 796 insertions(+), 331 deletions(-) create mode 100644 noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/errors.rs create mode 100644 noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/scan.rs create mode 100644 noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/value.rs diff --git a/.noir-sync-commit b/.noir-sync-commit index 2a6270fb774..5aba57a74d0 100644 --- a/.noir-sync-commit +++ b/.noir-sync-commit @@ -1 +1 @@ -9704bd0abfe2dba1e7a4aef6cdb6cc83d70b929e +5985e4285de9e29f7c986103a49fdaec59228887 diff --git a/noir/noir-repo/.github/actions/install-playwright/action.yml b/noir/noir-repo/.github/actions/install-playwright/action.yml index be835a422cc..a70c45d152a 100644 --- a/noir/noir-repo/.github/actions/install-playwright/action.yml +++ b/noir/noir-repo/.github/actions/install-playwright/action.yml @@ -19,5 +19,8 @@ runs: - name: Install playwright deps shell: bash if: steps.playwright-cache.outputs.cache-hit != 'true' - run: ./.github/scripts/playwright-install.sh + run: | + # Workaround: https://github.com/microsoft/playwright/issues/30503#issuecomment-2074783821 + sudo rm /etc/apt/sources.list.d/microsoft-prod.list + ./.github/scripts/playwright-install.sh diff --git a/noir/noir-repo/.github/workflows/gates_report.yml b/noir/noir-repo/.github/workflows/gates_report.yml index e694e5fad04..ba4cb600c59 100644 --- a/noir/noir-repo/.github/workflows/gates_report.yml +++ b/noir/noir-repo/.github/workflows/gates_report.yml @@ -71,10 +71,10 @@ jobs: run: | ./gates_report.sh mv gates_report.json ../gates_report.json - + - name: Compare gates reports id: gates_diff - uses: vezenovm/noir-gates-diff@f80ea702d579873ff80f0261c62e2bae5203748e + uses: vezenovm/noir-gates-diff@acf12797860f237117e15c0d6e08d64253af52b6 with: report: gates_report.json summaryQuantile: 0.9 # only display the 10% most significant circuit size diffs in the summary (defaults to 20%) diff --git a/noir/noir-repo/.github/workflows/test-js-packages.yml b/noir/noir-repo/.github/workflows/test-js-packages.yml index 7fd198d9a89..e6098dd269c 100644 --- a/noir/noir-repo/.github/workflows/test-js-packages.yml +++ b/noir/noir-repo/.github/workflows/test-js-packages.yml @@ -188,7 +188,7 @@ jobs: uses: ./.github/actions/setup - name: Install Playwright - run: ./.github/scripts/playwright-install.sh + uses: ./.github/actions/install-playwright - name: Run browser tests run: yarn workspace @noir-lang/acvm_js test:browser diff --git a/noir/noir-repo/Cargo.lock b/noir/noir-repo/Cargo.lock index 35702c8df03..9c9e13b57c9 100644 --- a/noir/noir-repo/Cargo.lock +++ b/noir/noir-repo/Cargo.lock @@ -782,9 +782,12 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.0.79" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] [[package]] name = "cfg-if" @@ -4089,12 +4092,27 @@ dependencies = [ "cc", "libc", "once_cell", - "spin", - "untrusted", + "spin 0.5.2", + "untrusted 0.7.1", "web-sys", "winapi", ] +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if 1.0.0", + "getrandom 0.2.10", + "libc", + "spin 0.9.8", + "untrusted 0.9.0", + "windows-sys 0.52.0", +] + [[package]] name = "rkyv" version = "0.7.42" @@ -4194,12 +4212,12 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.7" +version = "0.21.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd8d6c9f025a446bc4d18ad9632e69aec8f287aa84499ee335599fabd20c3fd8" +checksum = "7fecbfb7b1444f477b345853b1fce097a2c6fb637b2bfb87e6bc5db0f043fae4" dependencies = [ "log", - "ring", + "ring 0.17.8", "rustls-webpki", "sct", ] @@ -4215,12 +4233,12 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.101.4" +version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d93931baf2d282fff8d3a532bbfd7653f734643161b87e3e01e59a04439bf0d" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "ring", - "untrusted", + "ring 0.17.8", + "untrusted 0.9.0", ] [[package]] @@ -4361,8 +4379,8 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" dependencies = [ - "ring", - "untrusted", + "ring 0.16.20", + "untrusted 0.7.1", ] [[package]] @@ -4696,6 +4714,12 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + [[package]] name = "spki" version = "0.6.0" @@ -5341,6 +5365,12 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "url" version = "1.7.2" diff --git a/noir/noir-repo/acvm-repo/acvm_js/build.sh b/noir/noir-repo/acvm-repo/acvm_js/build.sh index 7ba69389a9b..ee93413ab85 100755 --- a/noir/noir-repo/acvm-repo/acvm_js/build.sh +++ b/noir/noir-repo/acvm-repo/acvm_js/build.sh @@ -25,6 +25,7 @@ function run_if_available { require_command jq require_command cargo require_command wasm-bindgen +# require_command wasm-opt self_path=$(dirname "$(readlink -f "$0")") pname=$(cargo read-manifest | jq -r '.name') @@ -48,3 +49,5 @@ BROWSER_WASM=${BROWSER_DIR}/${pname}_bg.wasm run_or_fail cargo build --lib --release --target $TARGET --package ${pname} run_or_fail wasm-bindgen $WASM_BINARY --out-dir $NODE_DIR --typescript --target nodejs run_or_fail wasm-bindgen $WASM_BINARY --out-dir $BROWSER_DIR --typescript --target web +run_if_available wasm-opt $NODE_WASM -o $NODE_WASM -O +run_if_available wasm-opt $BROWSER_WASM -o $BROWSER_WASM -O diff --git a/noir/noir-repo/aztec_macros/src/utils/hir_utils.rs b/noir/noir-repo/aztec_macros/src/utils/hir_utils.rs index 874640c01c8..3801ff1cc75 100644 --- a/noir/noir-repo/aztec_macros/src/utils/hir_utils.rs +++ b/noir/noir-repo/aztec_macros/src/utils/hir_utils.rs @@ -1,6 +1,8 @@ use iter_extended::vecmap; use noirc_errors::Location; use noirc_frontend::ast; +use noirc_frontend::macros_api::{HirExpression, HirLiteral}; +use noirc_frontend::node_interner::{NodeInterner, TraitImplKind}; use noirc_frontend::{ graph::CrateId, hir::{ @@ -8,11 +10,8 @@ use noirc_frontend::{ resolution::{path_resolver::StandardPathResolver, resolver::Resolver}, type_check::type_check_func, }, - macros_api::{ - FileId, HirContext, HirExpression, HirLiteral, MacroError, ModuleDefId, NodeInterner, - StructId, - }, - node_interner::{FuncId, TraitId, TraitImplKind}, + macros_api::{FileId, HirContext, MacroError, ModuleDefId, StructId}, + node_interner::{FuncId, TraitId}, Shared, StructType, Type, }; diff --git a/noir/noir-repo/compiler/noirc_frontend/src/ast/expression.rs b/noir/noir-repo/compiler/noirc_frontend/src/ast/expression.rs index 92c1add80a6..5659de46588 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/ast/expression.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/ast/expression.rs @@ -28,6 +28,7 @@ pub enum ExpressionKind { Lambda(Box), Parenthesized(Box), Quote(BlockExpression), + Comptime(BlockExpression), Error, } @@ -504,6 +505,7 @@ impl Display for ExpressionKind { Lambda(lambda) => lambda.fmt(f), Parenthesized(sub_expr) => write!(f, "({sub_expr})"), Quote(block) => write!(f, "quote {block}"), + Comptime(block) => write!(f, "comptime {block}"), Error => write!(f, "Error"), } } diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/errors.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/errors.rs new file mode 100644 index 00000000000..67d9a006b22 --- /dev/null +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/errors.rs @@ -0,0 +1,53 @@ +use crate::Type; +use acvm::FieldElement; +use noirc_errors::Location; + +use super::value::Value; + +/// The possible errors that can halt the interpreter. +#[derive(Debug)] +pub enum InterpreterError { + ArgumentCountMismatch { expected: usize, actual: usize, call_location: Location }, + TypeMismatch { expected: Type, value: Value, location: Location }, + NonComptimeVarReferenced { name: String, location: Location }, + IntegerOutOfRangeForType { value: FieldElement, typ: Type, location: Location }, + ErrorNodeEncountered { location: Location }, + NonFunctionCalled { value: Value, location: Location }, + NonBoolUsedInIf { value: Value, location: Location }, + NonBoolUsedInConstrain { value: Value, location: Location }, + FailingConstraint { message: Option, location: Location }, + NoMethodFound { object: Value, typ: Type, location: Location }, + NonIntegerUsedInLoop { value: Value, location: Location }, + NonPointerDereferenced { value: Value, location: Location }, + NonTupleOrStructInMemberAccess { value: Value, location: Location }, + NonArrayIndexed { value: Value, location: Location }, + NonIntegerUsedAsIndex { value: Value, location: Location }, + NonIntegerIntegerLiteral { typ: Type, location: Location }, + NonIntegerArrayLength { typ: Type, location: Location }, + NonNumericCasted { value: Value, location: Location }, + IndexOutOfBounds { index: usize, length: usize, location: Location }, + ExpectedStructToHaveField { value: Value, field_name: String, location: Location }, + TypeUnsupported { typ: Type, location: Location }, + InvalidValueForUnary { value: Value, operator: &'static str, location: Location }, + InvalidValuesForBinary { lhs: Value, rhs: Value, operator: &'static str, location: Location }, + CastToNonNumericType { typ: Type, location: Location }, + QuoteInRuntimeCode { location: Location }, + NonStructInConstructor { typ: Type, location: Location }, + CannotInlineMacro { value: Value, location: Location }, + UnquoteFoundDuringEvaluation { location: Location }, + + Unimplemented { item: &'static str, location: Location }, + + // Perhaps this should be unreachable! due to type checking also preventing this error? + // Currently it and the Continue variant are the only interpreter errors without a Location field + BreakNotInLoop { location: Location }, + ContinueNotInLoop { location: Location }, + + // These cases are not errors, they are just used to prevent us from running more code + // until the loop can be resumed properly. These cases will never be displayed to users. + Break, + Continue, +} + +#[allow(unused)] +pub(super) type IResult = std::result::Result; diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/hir_to_ast.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/hir_to_ast.rs index 47ca7083ff0..42ee76d29fa 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/hir_to_ast.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/hir_to_ast.rs @@ -9,7 +9,7 @@ use crate::ast::{ UnresolvedTypeData, UnresolvedTypeExpression, }; use crate::ast::{ConstrainStatement, Expression, Statement, StatementKind}; -use crate::hir_def::expr::{HirArrayLiteral, HirExpression, HirIdent}; +use crate::hir_def::expr::{HirArrayLiteral, HirBlockExpression, HirExpression, HirIdent}; use crate::hir_def::stmt::{HirLValue, HirPattern, HirStatement}; use crate::hir_def::types::Type; use crate::macros_api::HirLiteral; @@ -26,7 +26,7 @@ impl StmtId { #[allow(unused)] fn to_ast(self, interner: &NodeInterner) -> Statement { let statement = interner.statement(&self); - let span = interner.statement_span(&self); + let span = interner.statement_span(self); let kind = match statement { HirStatement::Let(let_stmt) => { @@ -108,10 +108,7 @@ impl ExprId { ExpressionKind::Literal(Literal::FmtStr(string)) } HirExpression::Literal(HirLiteral::Unit) => ExpressionKind::Literal(Literal::Unit), - HirExpression::Block(expr) => { - let statements = vecmap(expr.statements, |statement| statement.to_ast(interner)); - ExpressionKind::Block(BlockExpression { statements }) - } + HirExpression::Block(expr) => ExpressionKind::Block(expr.into_ast(interner)), HirExpression::Prefix(prefix) => ExpressionKind::Prefix(Box::new(PrefixExpression { operator: prefix.operator, rhs: prefix.rhs.to_ast(interner), @@ -172,8 +169,12 @@ impl ExprId { let body = lambda.body.to_ast(interner); ExpressionKind::Lambda(Box::new(Lambda { parameters, return_type, body })) } - HirExpression::Quote(block) => ExpressionKind::Quote(block), HirExpression::Error => ExpressionKind::Error, + HirExpression::Comptime(block) => ExpressionKind::Comptime(block.into_ast(interner)), + HirExpression::Quote(block) => ExpressionKind::Quote(block), + + // A macro was evaluated here! + HirExpression::Unquote(block) => ExpressionKind::Block(block), }; Expression::new(kind, span) @@ -353,3 +354,10 @@ impl HirArrayLiteral { } } } + +impl HirBlockExpression { + fn into_ast(self, interner: &NodeInterner) -> BlockExpression { + let statements = vecmap(self.statements, |statement| statement.to_ast(interner)); + BlockExpression { statements } + } +} diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/interpreter.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/interpreter.rs index 03839c2f0cd..c01c985a40c 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/interpreter.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/interpreter.rs @@ -1,12 +1,12 @@ -use std::{borrow::Cow, collections::hash_map::Entry, rc::Rc}; +use std::{collections::hash_map::Entry, rc::Rc}; use acvm::FieldElement; use im::Vector; -use iter_extended::{try_vecmap, vecmap}; +use iter_extended::try_vecmap; use noirc_errors::Location; use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet}; -use crate::ast::{BinaryOpKind, BlockExpression, FunctionKind, IntegerBitSize, Signedness}; +use crate::ast::{BinaryOpKind, FunctionKind, IntegerBitSize, Signedness}; use crate::{ hir_def::{ expr::{ @@ -22,12 +22,16 @@ use crate::{ }, macros_api::{HirExpression, HirLiteral, HirStatement, NodeInterner}, node_interner::{DefinitionId, DefinitionKind, ExprId, FuncId, StmtId}, + Shared, Type, TypeBinding, TypeBindings, TypeVariableKind, }; -use crate::{Shared, Type, TypeBinding, TypeBindings, TypeVariableKind}; + +use super::errors::{IResult, InterpreterError}; +use super::value::Value; + #[allow(unused)] -pub(crate) struct Interpreter<'interner> { +pub struct Interpreter<'interner> { /// To expand macros the Interpreter may mutate hir nodes within the NodeInterner - interner: &'interner mut NodeInterner, + pub(super) interner: &'interner mut NodeInterner, /// Each value currently in scope in the interpreter. /// Each element of the Vec represents a scope with every scope together making @@ -49,72 +53,6 @@ pub(crate) struct Interpreter<'interner> { in_comptime_context: bool, } -#[allow(unused)] -#[derive(Debug, Clone, PartialEq, Eq)] -pub(crate) enum Value { - Unit, - Bool(bool), - Field(FieldElement), - I8(i8), - I32(i32), - I64(i64), - U8(u8), - U32(u32), - U64(u64), - String(Rc), - Function(FuncId, Type), - Closure(HirLambda, Vec, Type), - Tuple(Vec), - Struct(HashMap, Value>, Type), - Pointer(Shared), - Array(Vector, Type), - Slice(Vector, Type), - Code(Rc), -} - -/// The possible errors that can halt the interpreter. -#[allow(unused)] -#[derive(Debug)] -pub(crate) enum InterpreterError { - ArgumentCountMismatch { expected: usize, actual: usize, call_location: Location }, - TypeMismatch { expected: Type, value: Value, location: Location }, - NoValueForId { id: DefinitionId, location: Location }, - IntegerOutOfRangeForType { value: FieldElement, typ: Type, location: Location }, - ErrorNodeEncountered { location: Location }, - NonFunctionCalled { value: Value, location: Location }, - NonBoolUsedInIf { value: Value, location: Location }, - NonBoolUsedInConstrain { value: Value, location: Location }, - FailingConstraint { message: Option, location: Location }, - NoMethodFound { object: Value, typ: Type, location: Location }, - NonIntegerUsedInLoop { value: Value, location: Location }, - NonPointerDereferenced { value: Value, location: Location }, - NonTupleOrStructInMemberAccess { value: Value, location: Location }, - NonArrayIndexed { value: Value, location: Location }, - NonIntegerUsedAsIndex { value: Value, location: Location }, - NonIntegerIntegerLiteral { typ: Type, location: Location }, - NonIntegerArrayLength { typ: Type, location: Location }, - NonNumericCasted { value: Value, location: Location }, - IndexOutOfBounds { index: usize, length: usize, location: Location }, - ExpectedStructToHaveField { value: Value, field_name: String, location: Location }, - TypeUnsupported { typ: Type, location: Location }, - InvalidValueForUnary { value: Value, operator: &'static str, location: Location }, - InvalidValuesForBinary { lhs: Value, rhs: Value, operator: &'static str, location: Location }, - CastToNonNumericType { typ: Type, location: Location }, - - // Perhaps this should be unreachable! due to type checking also preventing this error? - // Currently it and the Continue variant are the only interpreter errors without a Location field - BreakNotInLoop, - ContinueNotInLoop, - - // These cases are not errors but prevent us from running more code - // until the loop can be resumed properly. - Break, - Continue, -} - -#[allow(unused)] -type IResult = std::result::Result; - #[allow(unused)] impl<'a> Interpreter<'a> { pub(crate) fn new(interner: &'a mut NodeInterner) -> Self { @@ -193,14 +131,14 @@ impl<'a> Interpreter<'a> { /// Enters a function, pushing a new scope and resetting any required state. /// Returns the previous values of the internal state, to be reset when /// `exit_function` is called. - fn enter_function(&mut self) -> (bool, Vec>) { + pub(super) fn enter_function(&mut self) -> (bool, Vec>) { // Drain every scope except the global scope let scope = self.scopes.drain(1..).collect(); self.push_scope(); (std::mem::take(&mut self.in_loop), scope) } - fn exit_function(&mut self, mut state: (bool, Vec>)) { + pub(super) fn exit_function(&mut self, mut state: (bool, Vec>)) { self.in_loop = state.0; // Keep only the global scope @@ -208,11 +146,11 @@ impl<'a> Interpreter<'a> { self.scopes.append(&mut state.1); } - fn push_scope(&mut self) { + pub(super) fn push_scope(&mut self) { self.scopes.push(HashMap::default()); } - fn pop_scope(&mut self) { + pub(super) fn pop_scope(&mut self) { self.scopes.pop(); } @@ -308,13 +246,7 @@ impl<'a> Interpreter<'a> { location: Location, ) -> IResult<()> { self.type_check(typ, &argument, location)?; - for scope in self.scopes.iter_mut().rev() { - if let Entry::Occupied(mut entry) = scope.entry(id) { - entry.insert(argument); - return Ok(()); - } - } - Err(InterpreterError::NoValueForId { id, location }) + self.mutate(id, argument, location) } /// Mutate an existing variable, potentially from a prior scope @@ -325,17 +257,12 @@ impl<'a> Interpreter<'a> { return Ok(()); } } - Err(InterpreterError::NoValueForId { id, location }) + let name = self.interner.definition(id).name.clone(); + Err(InterpreterError::NonComptimeVarReferenced { name, location }) } fn lookup(&self, ident: &HirIdent) -> IResult { - for scope in self.scopes.iter().rev() { - if let Some(value) = scope.get(&ident.id) { - return Ok(value.clone()); - } - } - - Err(InterpreterError::NoValueForId { id: ident.id, location: ident.location }) + self.lookup_id(ident.id, ident.location) } fn lookup_id(&self, id: DefinitionId, location: Location) -> IResult { @@ -345,7 +272,12 @@ impl<'a> Interpreter<'a> { } } - Err(InterpreterError::NoValueForId { id, location }) + // Justification for `NonComptimeVarReferenced`: + // If we have an id to lookup at all that means name resolution successfully + // found another variable in scope for this name. If the name is in scope + // but unknown by the interpreter it must be because it was not a comptime variable. + let name = self.interner.definition(id).name.clone(); + Err(InterpreterError::NonComptimeVarReferenced { name, location }) } fn type_check(&self, typ: &Type, value: &Value, location: Location) -> IResult<()> { @@ -375,6 +307,13 @@ impl<'a> Interpreter<'a> { HirExpression::Tuple(tuple) => self.evaluate_tuple(tuple), HirExpression::Lambda(lambda) => self.evaluate_lambda(lambda, id), HirExpression::Quote(block) => Ok(Value::Code(Rc::new(block))), + HirExpression::Comptime(block) => self.evaluate_block(block), + HirExpression::Unquote(block) => { + // An Unquote expression being found is indicative of a macro being + // expanded within another comptime fn which we don't currently support. + let location = self.interner.expr_location(&id); + Err(InterpreterError::UnquoteFoundDuringEvaluation { location }) + } HirExpression::Error => { let location = self.interner.expr_location(&id); Err(InterpreterError::ErrorNodeEncountered { location }) @@ -390,7 +329,7 @@ impl<'a> Interpreter<'a> { let typ = self.interner.id_type(id); Ok(Value::Function(*function_id, typ)) } - DefinitionKind::Local(_) => dbg!(self.lookup(&ident)), + DefinitionKind::Local(_) => self.lookup(&ident), DefinitionKind::Global(global_id) => { let let_ = self.interner.get_global_let_statement(*global_id).unwrap(); self.evaluate_let(let_)?; @@ -503,7 +442,7 @@ impl<'a> Interpreter<'a> { } } - fn evaluate_block(&mut self, mut block: HirBlockExpression) -> IResult { + pub(super) fn evaluate_block(&mut self, mut block: HirBlockExpression) -> IResult { let last_statement = block.statements.pop(); self.push_scope(); @@ -1075,8 +1014,8 @@ impl<'a> Interpreter<'a> { HirStatement::Constrain(constrain) => self.evaluate_constrain(constrain), HirStatement::Assign(assign) => self.evaluate_assign(assign), HirStatement::For(for_) => self.evaluate_for(for_), - HirStatement::Break => self.evaluate_break(), - HirStatement::Continue => self.evaluate_continue(), + HirStatement::Break => self.evaluate_break(statement), + HirStatement::Continue => self.evaluate_continue(statement), HirStatement::Expression(expression) => self.evaluate(expression), HirStatement::Comptime(statement) => self.evaluate_comptime(statement), HirStatement::Semi(expression) => { @@ -1236,59 +1175,28 @@ impl<'a> Interpreter<'a> { Ok(Value::Unit) } - fn evaluate_break(&mut self) -> IResult { + fn evaluate_break(&mut self, id: StmtId) -> IResult { if self.in_loop { Err(InterpreterError::Break) } else { - Err(InterpreterError::BreakNotInLoop) + let location = self.interner.statement_location(id); + Err(InterpreterError::BreakNotInLoop { location }) } } - fn evaluate_continue(&mut self) -> IResult { + fn evaluate_continue(&mut self, id: StmtId) -> IResult { if self.in_loop { Err(InterpreterError::Continue) } else { - Err(InterpreterError::ContinueNotInLoop) + let location = self.interner.statement_location(id); + Err(InterpreterError::ContinueNotInLoop { location }) } } - fn evaluate_comptime(&mut self, statement: StmtId) -> IResult { + pub(super) fn evaluate_comptime(&mut self, statement: StmtId) -> IResult { let was_in_comptime = std::mem::replace(&mut self.in_comptime_context, true); let result = self.evaluate_statement(statement); self.in_comptime_context = was_in_comptime; result } } - -impl Value { - fn get_type(&self) -> Cow { - Cow::Owned(match self { - Value::Unit => Type::Unit, - Value::Bool(_) => Type::Bool, - Value::Field(_) => Type::FieldElement, - Value::I8(_) => Type::Integer(Signedness::Signed, IntegerBitSize::Eight), - Value::I32(_) => Type::Integer(Signedness::Signed, IntegerBitSize::ThirtyTwo), - Value::I64(_) => Type::Integer(Signedness::Signed, IntegerBitSize::SixtyFour), - Value::U8(_) => Type::Integer(Signedness::Unsigned, IntegerBitSize::Eight), - Value::U32(_) => Type::Integer(Signedness::Unsigned, IntegerBitSize::ThirtyTwo), - Value::U64(_) => Type::Integer(Signedness::Unsigned, IntegerBitSize::SixtyFour), - Value::String(value) => { - let length = Type::Constant(value.len() as u64); - Type::String(Box::new(length)) - } - Value::Function(_, typ) => return Cow::Borrowed(typ), - Value::Closure(_, _, typ) => return Cow::Borrowed(typ), - Value::Tuple(fields) => { - Type::Tuple(vecmap(fields, |field| field.get_type().into_owned())) - } - Value::Struct(_, typ) => return Cow::Borrowed(typ), - Value::Array(_, typ) => return Cow::Borrowed(typ), - Value::Slice(_, typ) => return Cow::Borrowed(typ), - Value::Code(_) => Type::Code, - Value::Pointer(element) => { - let element = element.borrow().get_type().into_owned(); - Type::MutableReference(Box::new(element)) - } - }) - } -} diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/mod.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/mod.rs index 83aaddaa405..26e05d675b3 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/mod.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/mod.rs @@ -1,3 +1,8 @@ +mod errors; mod hir_to_ast; mod interpreter; +mod scan; mod tests; +mod value; + +pub use interpreter::Interpreter; diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/scan.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/scan.rs new file mode 100644 index 00000000000..50c8ccb4557 --- /dev/null +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/scan.rs @@ -0,0 +1,213 @@ +//! This module is for the scanning of the Hir by the interpreter. +//! In this initial step, the Hir is scanned for `Comptime` nodes +//! without actually executing anything until such a node is found. +//! Once such a node is found, the interpreter will call the relevant +//! evaluate method on that node type, insert the result into the Ast, +//! and continue scanning the rest of the program. +//! +//! Since it mostly just needs to recur on the Hir looking for Comptime +//! nodes, this pass is fairly simple. The only thing it really needs to +//! ensure to do is to push and pop scopes on the interpreter as needed +//! so that any variables defined within e.g. an `if` statement containing +//! a `Comptime` block aren't accessible outside of the `if`. +use crate::{ + hir_def::{ + expr::{ + HirArrayLiteral, HirBlockExpression, HirCallExpression, HirConstructorExpression, + HirIfExpression, HirIndexExpression, HirInfixExpression, HirLambda, + HirMethodCallExpression, + }, + stmt::HirForStatement, + }, + macros_api::{HirExpression, HirLiteral, HirStatement}, + node_interner::{ExprId, FuncId, StmtId}, +}; + +use super::{ + errors::{IResult, InterpreterError}, + interpreter::Interpreter, +}; + +#[allow(dead_code)] +impl<'interner> Interpreter<'interner> { + /// Scan through a function, evaluating any Comptime nodes found. + /// These nodes will be modified in place, replaced with the + /// result of their evaluation. + pub fn scan_function(&mut self, function: FuncId) -> IResult<()> { + // Don't scan through functions that are already comptime. They may use comptime-only + // features (most likely HirExpression::Quote) that we'd otherwise error for. + if self.interner.function_modifiers(&function).is_comptime { + return Ok(()); + } + + let function = self.interner.function(&function); + + let state = self.enter_function(); + self.scan_expression(function.as_expr())?; + self.exit_function(state); + Ok(()) + } + + fn scan_expression(&mut self, expr: ExprId) -> IResult<()> { + match self.interner.expression(&expr) { + HirExpression::Ident(_) => Ok(()), + HirExpression::Literal(literal) => self.scan_literal(literal), + HirExpression::Block(block) => self.scan_block(block), + HirExpression::Prefix(prefix) => self.scan_expression(prefix.rhs), + HirExpression::Infix(infix) => self.scan_infix(infix), + HirExpression::Index(index) => self.scan_index(index), + HirExpression::Constructor(constructor) => self.scan_constructor(constructor), + HirExpression::MemberAccess(member_access) => self.scan_expression(member_access.lhs), + HirExpression::Call(call) => self.scan_call(call), + HirExpression::MethodCall(method_call) => self.scan_method_call(method_call), + HirExpression::Cast(cast) => self.scan_expression(cast.lhs), + HirExpression::If(if_) => self.scan_if(if_), + HirExpression::Tuple(tuple) => self.scan_tuple(tuple), + HirExpression::Lambda(lambda) => self.scan_lambda(lambda), + HirExpression::Comptime(block) => { + let location = self.interner.expr_location(&expr); + let new_expr = + self.evaluate_block(block)?.into_expression(self.interner, location)?; + let new_expr = self.interner.expression(&new_expr); + self.interner.replace_expr(&expr, new_expr); + Ok(()) + } + HirExpression::Quote(_) => { + // This error could be detected much earlier in the compiler pipeline but + // it just makes sense for the comptime code to handle comptime things. + let location = self.interner.expr_location(&expr); + Err(InterpreterError::QuoteInRuntimeCode { location }) + } + HirExpression::Error => Ok(()), + + // Unquote should only be inserted by the comptime interpreter while expanding macros + // and is removed by the Hir -> Ast conversion pass which converts it into a normal block. + // If we find one now during scanning it most likely means the Hir -> Ast conversion + // missed it somehow. In the future we may allow users to manually write unquote + // expressions in their code but for now this is unreachable. + HirExpression::Unquote(block) => { + unreachable!("Found unquote block while scanning: {block}") + } + } + } + + fn scan_literal(&mut self, literal: HirLiteral) -> IResult<()> { + match literal { + HirLiteral::Array(elements) | HirLiteral::Slice(elements) => match elements { + HirArrayLiteral::Standard(elements) => { + for element in elements { + self.scan_expression(element)?; + } + Ok(()) + } + HirArrayLiteral::Repeated { repeated_element, length: _ } => { + self.scan_expression(repeated_element) + } + }, + HirLiteral::Bool(_) + | HirLiteral::Integer(_, _) + | HirLiteral::Str(_) + | HirLiteral::FmtStr(_, _) + | HirLiteral::Unit => Ok(()), + } + } + + fn scan_block(&mut self, block: HirBlockExpression) -> IResult<()> { + self.push_scope(); + for statement in &block.statements { + self.scan_statement(*statement)?; + } + self.pop_scope(); + Ok(()) + } + + fn scan_infix(&mut self, infix: HirInfixExpression) -> IResult<()> { + self.scan_expression(infix.lhs)?; + self.scan_expression(infix.rhs) + } + + fn scan_index(&mut self, index: HirIndexExpression) -> IResult<()> { + self.scan_expression(index.collection)?; + self.scan_expression(index.index) + } + + fn scan_constructor(&mut self, constructor: HirConstructorExpression) -> IResult<()> { + for (_, field) in constructor.fields { + self.scan_expression(field)?; + } + Ok(()) + } + + fn scan_call(&mut self, call: HirCallExpression) -> IResult<()> { + self.scan_expression(call.func)?; + for arg in call.arguments { + self.scan_expression(arg)?; + } + Ok(()) + } + + fn scan_method_call(&mut self, method_call: HirMethodCallExpression) -> IResult<()> { + self.scan_expression(method_call.object)?; + for arg in method_call.arguments { + self.scan_expression(arg)?; + } + Ok(()) + } + + fn scan_if(&mut self, if_: HirIfExpression) -> IResult<()> { + self.scan_expression(if_.condition)?; + + self.push_scope(); + self.scan_expression(if_.consequence)?; + self.pop_scope(); + + if let Some(alternative) = if_.alternative { + self.push_scope(); + self.scan_expression(alternative)?; + self.pop_scope(); + } + Ok(()) + } + + fn scan_tuple(&mut self, tuple: Vec) -> IResult<()> { + for field in tuple { + self.scan_expression(field)?; + } + Ok(()) + } + + fn scan_lambda(&mut self, lambda: HirLambda) -> IResult<()> { + self.scan_expression(lambda.body) + } + + fn scan_statement(&mut self, statement: StmtId) -> IResult<()> { + match self.interner.statement(&statement) { + HirStatement::Let(let_) => self.scan_expression(let_.expression), + HirStatement::Constrain(constrain) => self.scan_expression(constrain.0), + HirStatement::Assign(assign) => self.scan_expression(assign.expression), + HirStatement::For(for_) => self.scan_for(for_), + HirStatement::Break => Ok(()), + HirStatement::Continue => Ok(()), + HirStatement::Expression(expression) => self.scan_expression(expression), + HirStatement::Semi(semi) => self.scan_expression(semi), + HirStatement::Error => Ok(()), + HirStatement::Comptime(comptime) => { + let location = self.interner.statement_location(comptime); + let new_expr = + self.evaluate_comptime(comptime)?.into_expression(self.interner, location)?; + self.interner.replace_statement(statement, HirStatement::Expression(new_expr)); + Ok(()) + } + } + } + + fn scan_for(&mut self, for_: HirForStatement) -> IResult<()> { + // We don't need to set self.in_loop since we're not actually evaluating this loop. + // We just need to push a scope so that if there's a `comptime { .. }` expr inside this + // loop, any variables it defines aren't accessible outside of it. + self.push_scope(); + self.scan_expression(for_.block)?; + self.pop_scope(); + Ok(()) + } +} diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/tests.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/tests.rs index 016e7079886..1a84dae4a87 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/tests.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/tests.rs @@ -2,7 +2,9 @@ use noirc_errors::Location; -use super::interpreter::{Interpreter, InterpreterError, Value}; +use super::errors::InterpreterError; +use super::interpreter::Interpreter; +use super::value::Value; use crate::hir::type_check::test::type_check_src_code; fn interpret_helper(src: &str, func_namespace: Vec) -> Result { diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/value.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/value.rs new file mode 100644 index 00000000000..d7af4643192 --- /dev/null +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/value.rs @@ -0,0 +1,169 @@ +use std::{borrow::Cow, rc::Rc}; + +use acvm::FieldElement; +use im::Vector; +use iter_extended::{try_vecmap, vecmap}; +use noirc_errors::Location; + +use crate::{ + ast::{BlockExpression, Ident, IntegerBitSize, Signedness}, + hir_def::expr::{HirArrayLiteral, HirConstructorExpression, HirIdent, HirLambda, ImplKind}, + macros_api::{HirExpression, HirLiteral, NodeInterner}, + node_interner::{ExprId, FuncId}, + Shared, Type, +}; +use rustc_hash::FxHashMap as HashMap; + +use super::errors::{IResult, InterpreterError}; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum Value { + Unit, + Bool(bool), + Field(FieldElement), + I8(i8), + I32(i32), + I64(i64), + U8(u8), + U32(u32), + U64(u64), + String(Rc), + Function(FuncId, Type), + Closure(HirLambda, Vec, Type), + Tuple(Vec), + Struct(HashMap, Value>, Type), + Pointer(Shared), + Array(Vector, Type), + Slice(Vector, Type), + Code(Rc), +} + +impl Value { + pub(crate) fn get_type(&self) -> Cow { + Cow::Owned(match self { + Value::Unit => Type::Unit, + Value::Bool(_) => Type::Bool, + Value::Field(_) => Type::FieldElement, + Value::I8(_) => Type::Integer(Signedness::Signed, IntegerBitSize::Eight), + Value::I32(_) => Type::Integer(Signedness::Signed, IntegerBitSize::ThirtyTwo), + Value::I64(_) => Type::Integer(Signedness::Signed, IntegerBitSize::SixtyFour), + Value::U8(_) => Type::Integer(Signedness::Unsigned, IntegerBitSize::Eight), + Value::U32(_) => Type::Integer(Signedness::Unsigned, IntegerBitSize::ThirtyTwo), + Value::U64(_) => Type::Integer(Signedness::Unsigned, IntegerBitSize::SixtyFour), + Value::String(value) => { + let length = Type::Constant(value.len() as u64); + Type::String(Box::new(length)) + } + Value::Function(_, typ) => return Cow::Borrowed(typ), + Value::Closure(_, _, typ) => return Cow::Borrowed(typ), + Value::Tuple(fields) => { + Type::Tuple(vecmap(fields, |field| field.get_type().into_owned())) + } + Value::Struct(_, typ) => return Cow::Borrowed(typ), + Value::Array(_, typ) => return Cow::Borrowed(typ), + Value::Slice(_, typ) => return Cow::Borrowed(typ), + Value::Code(_) => Type::Code, + Value::Pointer(element) => { + let element = element.borrow().get_type().into_owned(); + Type::MutableReference(Box::new(element)) + } + }) + } + + pub(crate) fn into_expression( + self, + interner: &mut NodeInterner, + location: Location, + ) -> IResult { + let typ = self.get_type().into_owned(); + + let expression = match self { + Value::Unit => HirExpression::Literal(HirLiteral::Unit), + Value::Bool(value) => HirExpression::Literal(HirLiteral::Bool(value)), + Value::Field(value) => HirExpression::Literal(HirLiteral::Integer(value, false)), + Value::I8(value) => { + let negative = value < 0; + let value = value.abs(); + let value = (value as u128).into(); + HirExpression::Literal(HirLiteral::Integer(value, negative)) + } + Value::I32(value) => { + let negative = value < 0; + let value = value.abs(); + let value = (value as u128).into(); + HirExpression::Literal(HirLiteral::Integer(value, negative)) + } + Value::I64(value) => { + let negative = value < 0; + let value = value.abs(); + let value = (value as u128).into(); + HirExpression::Literal(HirLiteral::Integer(value, negative)) + } + Value::U8(value) => { + HirExpression::Literal(HirLiteral::Integer((value as u128).into(), false)) + } + Value::U32(value) => { + HirExpression::Literal(HirLiteral::Integer((value as u128).into(), false)) + } + Value::U64(value) => { + HirExpression::Literal(HirLiteral::Integer((value as u128).into(), false)) + } + Value::String(value) => HirExpression::Literal(HirLiteral::Str(unwrap_rc(value))), + Value::Function(id, _typ) => { + let id = interner.function_definition_id(id); + let impl_kind = ImplKind::NotATraitMethod; + HirExpression::Ident(HirIdent { location, id, impl_kind }) + } + Value::Closure(_lambda, _env, _typ) => { + // TODO: How should a closure's environment be inlined? + let item = "returning closures from a comptime fn"; + return Err(InterpreterError::Unimplemented { item, location }); + } + Value::Tuple(fields) => { + let fields = try_vecmap(fields, |field| field.into_expression(interner, location))?; + HirExpression::Tuple(fields) + } + Value::Struct(fields, typ) => { + let fields = try_vecmap(fields, |(name, field)| { + let field = field.into_expression(interner, location)?; + Ok((Ident::new(unwrap_rc(name), location.span), field)) + })?; + + let (r#type, struct_generics) = match typ.follow_bindings() { + Type::Struct(def, generics) => (def, generics), + _ => return Err(InterpreterError::NonStructInConstructor { typ, location }), + }; + + HirExpression::Constructor(HirConstructorExpression { + r#type, + struct_generics, + fields, + }) + } + Value::Array(elements, _) => { + let elements = + try_vecmap(elements, |elements| elements.into_expression(interner, location))?; + HirExpression::Literal(HirLiteral::Array(HirArrayLiteral::Standard(elements))) + } + Value::Slice(elements, _) => { + let elements = + try_vecmap(elements, |elements| elements.into_expression(interner, location))?; + HirExpression::Literal(HirLiteral::Slice(HirArrayLiteral::Standard(elements))) + } + Value::Code(block) => HirExpression::Unquote(unwrap_rc(block)), + Value::Pointer(_) => { + return Err(InterpreterError::CannotInlineMacro { value: self, location }) + } + }; + + let id = interner.push_expr(expression); + interner.push_expr_location(id, location.span, location.file); + interner.push_expr_type(id, typ); + Ok(id) + } +} + +/// Unwraps an Rc value without cloning the inner value if the reference count is 1. Clones otherwise. +fn unwrap_rc(rc: Rc) -> T { + Rc::try_unwrap(rc).unwrap_or_else(|rc| (*rc).clone()) +} diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs index 4c6b5ab5885..7805f36cdb2 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs @@ -1,6 +1,7 @@ use super::dc_mod::collect_defs; use super::errors::{DefCollectorErrorKind, DuplicateType}; use crate::graph::CrateId; +use crate::hir::comptime::Interpreter; use crate::hir::def_map::{CrateDefMap, LocalModuleId, ModuleId}; use crate::hir::resolution::errors::ResolverError; @@ -30,6 +31,15 @@ use std::collections::{BTreeMap, HashMap}; use std::vec; +#[derive(Default)] +pub struct ResolvedModule { + pub globals: Vec<(FileId, GlobalId)>, + pub functions: Vec<(FileId, FuncId)>, + pub trait_impl_functions: Vec<(FileId, FuncId)>, + + pub errors: Vec<(CompilationError, FileId)>, +} + /// Stores all of the unresolved functions in a particular file/mod #[derive(Clone)] pub struct UnresolvedFunctions { @@ -304,6 +314,8 @@ impl DefCollector { } } + let mut resolved_module = ResolvedModule { errors, ..Default::default() }; + // We must first resolve and intern the globals before we can resolve any stmts inside each function. // Each function uses its own resolver with a newly created ScopeForest, and must be resolved again to be within a function's scope // @@ -312,21 +324,29 @@ impl DefCollector { let (literal_globals, other_globals) = filter_literal_globals(def_collector.collected_globals); - let mut resolved_globals = resolve_globals(context, literal_globals, crate_id); + resolved_module.resolve_globals(context, literal_globals, crate_id); - errors.extend(resolve_type_aliases( + resolved_module.errors.extend(resolve_type_aliases( context, def_collector.collected_type_aliases, crate_id, )); - errors.extend(resolve_traits(context, def_collector.collected_traits, crate_id)); + resolved_module.errors.extend(resolve_traits( + context, + def_collector.collected_traits, + crate_id, + )); // Must resolve structs before we resolve globals. - errors.extend(resolve_structs(context, def_collector.collected_types, crate_id)); + resolved_module.errors.extend(resolve_structs( + context, + def_collector.collected_types, + crate_id, + )); // Bind trait impls to their trait. Collect trait functions, that have a // default implementation, which hasn't been overridden. - errors.extend(collect_trait_impls( + resolved_module.errors.extend(collect_trait_impls( context, crate_id, &mut def_collector.collected_traits_impls, @@ -339,54 +359,55 @@ impl DefCollector { // // These are resolved after trait impls so that struct methods are chosen // over trait methods if there are name conflicts. - errors.extend(collect_impls(context, crate_id, &def_collector.collected_impls)); + resolved_module.errors.extend(collect_impls( + context, + crate_id, + &def_collector.collected_impls, + )); // We must wait to resolve non-integer globals until after we resolve structs since struct // globals will need to reference the struct type they're initialized to to ensure they are valid. - resolved_globals.extend(resolve_globals(context, other_globals, crate_id)); - errors.extend(resolved_globals.errors); + resolved_module.resolve_globals(context, other_globals, crate_id); // Resolve each function in the crate. This is now possible since imports have been resolved - let mut functions = Vec::new(); - functions.extend(resolve_free_functions( + resolved_module.functions = resolve_free_functions( &mut context.def_interner, crate_id, &context.def_maps, def_collector.collected_functions, None, - &mut errors, - )); + &mut resolved_module.errors, + ); - functions.extend(resolve_impls( + resolved_module.functions.extend(resolve_impls( &mut context.def_interner, crate_id, &context.def_maps, def_collector.collected_impls, - &mut errors, + &mut resolved_module.errors, )); - let impl_functions = resolve_trait_impls( + resolved_module.trait_impl_functions = resolve_trait_impls( context, def_collector.collected_traits_impls, crate_id, - &mut errors, + &mut resolved_module.errors, ); for macro_processor in macro_processors { macro_processor.process_typed_ast(&crate_id, context).unwrap_or_else( |(macro_err, file_id)| { - errors.push((macro_err.into(), file_id)); + resolved_module.errors.push((macro_err.into(), file_id)); }, ); } - errors.extend(context.def_interner.check_for_dependency_cycles()); + resolved_module.errors.extend(context.def_interner.check_for_dependency_cycles()); - errors.extend(type_check_globals(&mut context.def_interner, resolved_globals.globals)); - errors.extend(type_check_functions(&mut context.def_interner, functions)); - errors.extend(type_check_trait_impl_signatures(&mut context.def_interner, &impl_functions)); - errors.extend(type_check_functions(&mut context.def_interner, impl_functions)); - errors + resolved_module.type_check(context); + resolved_module.evaluate_comptime(&mut context.def_interner); + + resolved_module.errors } } @@ -444,48 +465,59 @@ fn filter_literal_globals( }) } -fn type_check_globals( - interner: &mut NodeInterner, - global_ids: Vec<(FileId, GlobalId)>, -) -> Vec<(CompilationError, fm::FileId)> { - global_ids - .into_iter() - .flat_map(|(file_id, global_id)| { - TypeChecker::check_global(global_id, interner) - .iter() - .cloned() - .map(|e| (e.into(), file_id)) - .collect::>() - }) - .collect() -} +impl ResolvedModule { + fn type_check(&mut self, context: &mut Context) { + self.type_check_globals(&mut context.def_interner); + self.type_check_functions(&mut context.def_interner); + self.type_check_trait_impl_function(&mut context.def_interner); + } -fn type_check_functions( - interner: &mut NodeInterner, - file_func_ids: Vec<(FileId, FuncId)>, -) -> Vec<(CompilationError, fm::FileId)> { - file_func_ids - .into_iter() - .flat_map(|(file, func)| { - type_check_func(interner, func) - .into_iter() - .map(|e| (e.into(), file)) - .collect::>() - }) - .collect() -} + fn type_check_globals(&mut self, interner: &mut NodeInterner) { + for (file_id, global_id) in self.globals.iter() { + for error in TypeChecker::check_global(*global_id, interner) { + self.errors.push((error.into(), *file_id)); + } + } + } + + fn type_check_functions(&mut self, interner: &mut NodeInterner) { + for (file, func) in self.functions.iter() { + for error in type_check_func(interner, *func) { + self.errors.push((error.into(), *file)); + } + } + } + + fn type_check_trait_impl_function(&mut self, interner: &mut NodeInterner) { + for (file, func) in self.trait_impl_functions.iter() { + for error in check_trait_impl_method_matches_declaration(interner, *func) { + self.errors.push((error.into(), *file)); + } + for error in type_check_func(interner, *func) { + self.errors.push((error.into(), *file)); + } + } + } + + /// Evaluate all `comptime` expressions in this module + fn evaluate_comptime(&self, interner: &mut NodeInterner) { + let mut interpreter = Interpreter::new(interner); + + for (_file, function) in &self.functions { + // .unwrap() is temporary here until we can convert + // from InterpreterError to (CompilationError, FileId) + interpreter.scan_function(*function).unwrap(); + } + } -fn type_check_trait_impl_signatures( - interner: &mut NodeInterner, - file_func_ids: &[(FileId, FuncId)], -) -> Vec<(CompilationError, fm::FileId)> { - file_func_ids - .iter() - .flat_map(|(file, func)| { - check_trait_impl_method_matches_declaration(interner, *func) - .into_iter() - .map(|e| (e.into(), *file)) - .collect::>() - }) - .collect() + fn resolve_globals( + &mut self, + context: &mut Context, + literal_globals: Vec, + crate_id: CrateId, + ) { + let globals = resolve_globals(context, literal_globals, crate_id); + self.globals.extend(globals.globals); + self.errors.extend(globals.errors); + } } diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/globals.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/globals.rs index 9fb31271727..bcda4e75d3d 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/globals.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/globals.rs @@ -11,18 +11,12 @@ use crate::{ use fm::FileId; use iter_extended::vecmap; +#[derive(Default)] pub(crate) struct ResolvedGlobals { pub(crate) globals: Vec<(FileId, GlobalId)>, pub(crate) errors: Vec<(CompilationError, FileId)>, } -impl ResolvedGlobals { - pub(crate) fn extend(&mut self, oth: Self) { - self.globals.extend(oth.globals); - self.errors.extend(oth.errors); - } -} - pub(crate) fn resolve_globals( context: &mut Context, globals: Vec, diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/resolver.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/resolver.rs index 0e69b3bdeba..8e29f8f9fce 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/resolver.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/resolver.rs @@ -1323,7 +1323,9 @@ impl<'a> Resolver<'a> { pub fn intern_stmt(&mut self, stmt: Statement) -> StmtId { let hir_stmt = self.resolve_stmt(stmt.kind, stmt.span); - self.interner.push_stmt(hir_stmt) + let id = self.interner.push_stmt(hir_stmt); + self.interner.push_statement_location(id, stmt.span, self.file); + id } fn resolve_lvalue(&mut self, lvalue: LValue) -> HirLValue { @@ -1531,7 +1533,9 @@ impl<'a> Resolver<'a> { collection: self.resolve_expression(indexed_expr.collection), index: self.resolve_expression(indexed_expr.index), }), - ExpressionKind::Block(block_expr) => self.resolve_block(block_expr), + ExpressionKind::Block(block_expr) => { + HirExpression::Block(self.resolve_block(block_expr)) + } ExpressionKind::Constructor(constructor) => { let span = constructor.type_name.span(); @@ -1598,6 +1602,7 @@ impl<'a> Resolver<'a> { // The quoted expression isn't resolved since we don't want errors if variables aren't defined ExpressionKind::Quote(block) => HirExpression::Quote(block), + ExpressionKind::Comptime(block) => HirExpression::Comptime(self.resolve_block(block)), }; // If these lines are ever changed, make sure to change the early return @@ -1930,14 +1935,14 @@ impl<'a> Resolver<'a> { Ok(path_resolution.module_def_id) } - fn resolve_block(&mut self, block_expr: BlockExpression) -> HirExpression { + fn resolve_block(&mut self, block_expr: BlockExpression) -> HirBlockExpression { let statements = self.in_new_scope(|this| vecmap(block_expr.statements, |stmt| this.intern_stmt(stmt))); - HirExpression::Block(HirBlockExpression { statements }) + HirBlockExpression { statements } } pub fn intern_block(&mut self, block: BlockExpression) -> ExprId { - let hir_block = self.resolve_block(block); + let hir_block = HirExpression::Block(self.resolve_block(block)); self.interner.push_expr(hir_block) } diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/type_check/expr.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/type_check/expr.rs index 62330732be4..0bc7673e105 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir/type_check/expr.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/type_check/expr.rs @@ -6,8 +6,8 @@ use crate::{ hir::{resolution::resolver::verify_mutable_reference, type_check::errors::Source}, hir_def::{ expr::{ - self, HirArrayLiteral, HirBinaryOp, HirExpression, HirIdent, HirLiteral, - HirMethodCallExpression, HirMethodReference, HirPrefixExpression, ImplKind, + self, HirArrayLiteral, HirBinaryOp, HirBlockExpression, HirExpression, HirIdent, + HirLiteral, HirMethodCallExpression, HirMethodReference, HirPrefixExpression, ImplKind, }, types::Type, }, @@ -271,34 +271,7 @@ impl<'interner> TypeChecker<'interner> { let span = self.interner.expr_span(expr_id); self.check_cast(lhs_type, cast_expr.r#type, span) } - HirExpression::Block(block_expr) => { - let mut block_type = Type::Unit; - - let statements = block_expr.statements(); - for (i, stmt) in statements.iter().enumerate() { - let expr_type = self.check_statement(stmt); - - if let crate::hir_def::stmt::HirStatement::Semi(expr) = - self.interner.statement(stmt) - { - let inner_expr_type = self.interner.id_type(expr); - let span = self.interner.expr_span(&expr); - - self.unify(&inner_expr_type, &Type::Unit, || { - TypeCheckError::UnusedResultError { - expr_type: inner_expr_type.clone(), - expr_span: span, - } - }); - } - - if i + 1 == statements.len() { - block_type = expr_type; - } - } - - block_type - } + HirExpression::Block(block_expr) => self.check_block(block_expr), HirExpression::Prefix(prefix_expr) => { let rhs_type = self.check_expression(&prefix_expr.rhs); let span = self.interner.expr_span(&prefix_expr.rhs); @@ -336,12 +309,44 @@ impl<'interner> TypeChecker<'interner> { Type::Function(params, Box::new(lambda.return_type), Box::new(env_type)) } HirExpression::Quote(_) => Type::Code, + HirExpression::Comptime(block) => self.check_block(block), + + // Unquote should be inserted & removed by the comptime interpreter. + // Even if we allowed it here, we wouldn't know what type to give to the result. + HirExpression::Unquote(block) => { + unreachable!("Unquote remaining during type checking {block}") + } }; self.interner.push_expr_type(*expr_id, typ.clone()); typ } + fn check_block(&mut self, block: HirBlockExpression) -> Type { + let mut block_type = Type::Unit; + + let statements = block.statements(); + for (i, stmt) in statements.iter().enumerate() { + let expr_type = self.check_statement(stmt); + + if let crate::hir_def::stmt::HirStatement::Semi(expr) = self.interner.statement(stmt) { + let inner_expr_type = self.interner.id_type(expr); + let span = self.interner.expr_span(&expr); + + self.unify(&inner_expr_type, &Type::Unit, || TypeCheckError::UnusedResultError { + expr_type: inner_expr_type.clone(), + expr_span: span, + }); + } + + if i + 1 == statements.len() { + block_type = expr_type; + } + } + + block_type + } + /// Returns the type of the given identifier fn check_ident(&mut self, ident: HirIdent, expr_id: &ExprId) -> Type { let mut bindings = TypeBindings::new(); diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir_def/expr.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir_def/expr.rs index d88b65d1fce..bf7d9b7b4ba 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir_def/expr.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir_def/expr.rs @@ -31,8 +31,10 @@ pub enum HirExpression { If(HirIfExpression), Tuple(Vec), Lambda(HirLambda), - Error, Quote(crate::ast::BlockExpression), + Unquote(crate::ast::BlockExpression), + Comptime(HirBlockExpression), + Error, } impl HirExpression { diff --git a/noir/noir-repo/compiler/noirc_frontend/src/lexer/token.rs b/noir/noir-repo/compiler/noirc_frontend/src/lexer/token.rs index ec513d55299..0242fc7e7ff 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/lexer/token.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/lexer/token.rs @@ -811,7 +811,7 @@ pub enum Keyword { Break, CallData, Char, - CompTime, + Comptime, Constrain, Continue, Contract, @@ -856,7 +856,7 @@ impl fmt::Display for Keyword { Keyword::Break => write!(f, "break"), Keyword::Char => write!(f, "char"), Keyword::CallData => write!(f, "call_data"), - Keyword::CompTime => write!(f, "comptime"), + Keyword::Comptime => write!(f, "comptime"), Keyword::Constrain => write!(f, "constrain"), Keyword::Continue => write!(f, "continue"), Keyword::Contract => write!(f, "contract"), @@ -904,7 +904,7 @@ impl Keyword { "break" => Keyword::Break, "call_data" => Keyword::CallData, "char" => Keyword::Char, - "comptime" => Keyword::CompTime, + "comptime" => Keyword::Comptime, "constrain" => Keyword::Constrain, "continue" => Keyword::Continue, "contract" => Keyword::Contract, diff --git a/noir/noir-repo/compiler/noirc_frontend/src/monomorphization/mod.rs b/noir/noir-repo/compiler/noirc_frontend/src/monomorphization/mod.rs index 74a0dd855c0..b130af9d125 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/monomorphization/mod.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/monomorphization/mod.rs @@ -521,6 +521,12 @@ impl<'interner> Monomorphizer<'interner> { } HirExpression::Error => unreachable!("Encountered Error node during monomorphization"), HirExpression::Quote(_) => unreachable!("quote expression remaining in runtime code"), + HirExpression::Unquote(_) => { + unreachable!("unquote expression remaining in runtime code") + } + HirExpression::Comptime(_) => { + unreachable!("comptime expression remaining in runtime code") + } }; Ok(expr) diff --git a/noir/noir-repo/compiler/noirc_frontend/src/node_interner.rs b/noir/noir-repo/compiler/noirc_frontend/src/node_interner.rs index b0e68be4868..9d3a79820dc 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/node_interner.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/node_interner.rs @@ -921,10 +921,18 @@ impl NodeInterner { self.id_location(expr_id) } - pub fn statement_span(&self, stmt_id: &StmtId) -> Span { + pub fn statement_span(&self, stmt_id: StmtId) -> Span { self.id_location(stmt_id).span } + pub fn statement_location(&self, stmt_id: StmtId) -> Location { + self.id_location(stmt_id) + } + + pub fn push_statement_location(&mut self, id: StmtId, span: Span, file: FileId) { + self.id_to_location.insert(id.into(), Location::new(span, file)); + } + pub fn get_struct(&self, id: StructId) -> Shared { self.structs[&id].clone() } diff --git a/noir/noir-repo/compiler/noirc_frontend/src/noir_parser.lalrpop b/noir/noir-repo/compiler/noirc_frontend/src/noir_parser.lalrpop index ec2b4c8ab46..9acb5ef8b58 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/noir_parser.lalrpop +++ b/noir/noir-repo/compiler/noirc_frontend/src/noir_parser.lalrpop @@ -61,7 +61,7 @@ extern { "break" => BorrowedToken::Keyword(noir_token::Keyword::Break), "call_data" => BorrowedToken::Keyword(noir_token::Keyword::CallData), "char" => BorrowedToken::Keyword(noir_token::Keyword::Char), - "comptime" => BorrowedToken::Keyword(noir_token::Keyword::CompTime), + "comptime" => BorrowedToken::Keyword(noir_token::Keyword::Comptime), "constrain" => BorrowedToken::Keyword(noir_token::Keyword::Constrain), "continue" => BorrowedToken::Keyword(noir_token::Keyword::Continue), "contract" => BorrowedToken::Keyword(noir_token::Keyword::Contract), diff --git a/noir/noir-repo/compiler/noirc_frontend/src/parser/parser.rs b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser.rs index 603193d1593..6e9f3969297 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/parser/parser.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser.rs @@ -532,7 +532,7 @@ where P2: ExprParser + 'a, S: NoirParser + 'a, { - keyword(Keyword::CompTime) + keyword(Keyword::Comptime) .ignore_then(choice(( declaration(expr), for_loop(expr_no_constructors, statement.clone()), @@ -548,7 +548,7 @@ fn comptime_expr<'a, S>(statement: S) -> impl NoirParser + 'a where S: NoirParser + 'a, { - keyword(Keyword::CompTime).ignore_then(block(statement)).map(ExpressionKind::Block) + keyword(Keyword::Comptime).ignore_then(block(statement)).map(ExpressionKind::Comptime) } fn declaration<'a, P>(expr_parser: P) -> impl NoirParser + 'a @@ -733,7 +733,7 @@ fn optional_distinctness() -> impl NoirParser { } fn maybe_comp_time() -> impl NoirParser { - keyword(Keyword::CompTime).or_not().validate(|opt, span, emit| { + keyword(Keyword::Comptime).or_not().validate(|opt, span, emit| { if opt.is_some() { emit(ParserError::with_reason( ParserErrorReason::ExperimentalFeature("comptime"), diff --git a/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/types.rs b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/types.rs index d8a63d161b9..82dd3dad681 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/types.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/types.rs @@ -12,7 +12,7 @@ use chumsky::prelude::*; use noirc_errors::Span; fn maybe_comp_time() -> impl NoirParser<()> { - keyword(Keyword::CompTime).or_not().validate(|opt, span, emit| { + keyword(Keyword::Comptime).or_not().validate(|opt, span, emit| { if opt.is_some() { emit(ParserError::with_reason(ParserErrorReason::ComptimeDeprecated, span)); } diff --git a/noir/noir-repo/noir_stdlib/src/bigint.nr b/noir/noir-repo/noir_stdlib/src/bigint.nr index ee9f8e44625..81dad968bf7 100644 --- a/noir/noir-repo/noir_stdlib/src/bigint.nr +++ b/noir/noir-repo/noir_stdlib/src/bigint.nr @@ -3,16 +3,14 @@ use crate::cmp::Eq; global bn254_fq = &[0x47, 0xFD, 0x7C, 0xD8, 0x16, 0x8C, 0x20, 0x3C, 0x8d, 0xca, 0x71, 0x68, 0x91, 0x6a, 0x81, 0x97, 0x5d, 0x58, 0x81, 0x81, 0xb6, 0x45, 0x50, 0xb8, 0x29, 0xa0, 0x31, 0xe1, 0x72, 0x4e, 0x64, 0x30]; -global bn254_fr = &[0x01, 0x00, 0x00, 0x00, 0x3F, 0x59, 0x1F, 0x43, 0x09, 0x97, 0xB9, 0x79, 0x48, 0xE8, 0x33, 0x28, - 0x5D, 0x58, 0x81, 0x81, 0xB6, 0x45, 0x50, 0xB8, 0x29, 0xA0, 0x31, 0xE1, 0x72, 0x4E, 0x64, 0x30]; +global bn254_fr = &[1, 0, 0, 240, 147, 245, 225, 67, 145, 112, 185, 121, 72, 232, 51, 40, 93, 88, 129, 129, 182, 69, 80, 184, 41, 160, 49, 225, 114, 78, 100, 48]; global secpk1_fr = &[0x41, 0x41, 0x36, 0xD0, 0x8C, 0x5E, 0xD2, 0xBF, 0x3B, 0xA0, 0x48, 0xAF, 0xE6, 0xDC, 0xAE, 0xBA, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]; global secpk1_fq = &[0x2F, 0xFC, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]; global secpr1_fq = &[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF]; -global secpr1_fr = &[0x51, 0x25, 0x63, 0xFC, 0xC2, 0xCA, 0xB9, 0xF3, 0x84, 0x9E, 0x17, 0xA7, 0xAD, 0xFA, 0xE6, 0xBC, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,0xFF, 0xFF, 0xFF, 0xFF]; +global secpr1_fr = &[81, 37, 99, 252, 194, 202, 185, 243, 132, 158, 23, 167, 173, 250, 230, 188, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255]; // docs:start:big_int_definition struct BigInt { pointer: u32, @@ -149,8 +147,8 @@ impl BigField for Secpk1Fr { impl Add for Secpk1Fr { fn add(self: Self, other: Secpk1Fr) -> Secpk1Fr { - let a = BigInt::from_le_bytes(self.array.as_slice(), secpk1_fq); - let b = BigInt::from_le_bytes(other.array.as_slice(), secpk1_fq); + let a = BigInt::from_le_bytes(self.array.as_slice(), secpk1_fr); + let b = BigInt::from_le_bytes(other.array.as_slice(), secpk1_fr); Secpk1Fr { array: a.bigint_add(b).to_le_bytes() } @@ -158,8 +156,8 @@ impl Add for Secpk1Fr { } impl Sub for Secpk1Fr { fn sub(self: Self, other: Secpk1Fr) -> Secpk1Fr { - let a = BigInt::from_le_bytes(self.array.as_slice(), secpk1_fq); - let b = BigInt::from_le_bytes(other.array.as_slice(), secpk1_fq); + let a = BigInt::from_le_bytes(self.array.as_slice(), secpk1_fr); + let b = BigInt::from_le_bytes(other.array.as_slice(), secpk1_fr); Secpk1Fr { array: a.bigint_sub(b).to_le_bytes() } @@ -167,8 +165,8 @@ impl Sub for Secpk1Fr { } impl Mul for Secpk1Fr { fn mul(self: Self, other: Secpk1Fr) -> Secpk1Fr { - let a = BigInt::from_le_bytes(self.array.as_slice(), secpk1_fq); - let b = BigInt::from_le_bytes(other.array.as_slice(), secpk1_fq); + let a = BigInt::from_le_bytes(self.array.as_slice(), secpk1_fr); + let b = BigInt::from_le_bytes(other.array.as_slice(), secpk1_fr); Secpk1Fr { array: a.bigint_mul(b).to_le_bytes() } @@ -176,8 +174,8 @@ impl Mul for Secpk1Fr { } impl Div for Secpk1Fr { fn div(self: Self, other: Secpk1Fr) -> Secpk1Fr { - let a = BigInt::from_le_bytes(self.array.as_slice(), secpk1_fq); - let b = BigInt::from_le_bytes(other.array.as_slice(), secpk1_fq); + let a = BigInt::from_le_bytes(self.array.as_slice(), secpk1_fr); + let b = BigInt::from_le_bytes(other.array.as_slice(), secpk1_fr); Secpk1Fr { array: a.bigint_div(b).to_le_bytes() } @@ -218,8 +216,8 @@ impl BigField for Bn254Fr { impl Add for Bn254Fr { fn add(self: Self, other: Bn254Fr) -> Bn254Fr { - let a = BigInt::from_le_bytes(self.array.as_slice(), secpk1_fq); - let b = BigInt::from_le_bytes(other.array.as_slice(), secpk1_fq); + let a = BigInt::from_le_bytes(self.array.as_slice(), bn254_fr); + let b = BigInt::from_le_bytes(other.array.as_slice(), bn254_fr); Bn254Fr { array: a.bigint_add(b).to_le_bytes() } @@ -227,8 +225,8 @@ impl Add for Bn254Fr { } impl Sub for Bn254Fr { fn sub(self: Self, other: Bn254Fr) -> Bn254Fr { - let a = BigInt::from_le_bytes(self.array.as_slice(), secpk1_fq); - let b = BigInt::from_le_bytes(other.array.as_slice(), secpk1_fq); + let a = BigInt::from_le_bytes(self.array.as_slice(), bn254_fr); + let b = BigInt::from_le_bytes(other.array.as_slice(), bn254_fr); Bn254Fr { array: a.bigint_sub(b).to_le_bytes() } @@ -236,8 +234,8 @@ impl Sub for Bn254Fr { } impl Mul for Bn254Fr { fn mul(self: Self, other: Bn254Fr) -> Bn254Fr { - let a = BigInt::from_le_bytes(self.array.as_slice(), secpk1_fq); - let b = BigInt::from_le_bytes(other.array.as_slice(), secpk1_fq); + let a = BigInt::from_le_bytes(self.array.as_slice(), bn254_fr); + let b = BigInt::from_le_bytes(other.array.as_slice(), bn254_fr); Bn254Fr { array: a.bigint_mul(b).to_le_bytes() } @@ -245,8 +243,8 @@ impl Mul for Bn254Fr { } impl Div for Bn254Fr { fn div(self: Self, other: Bn254Fr) -> Bn254Fr { - let a = BigInt::from_le_bytes(self.array.as_slice(), secpk1_fq); - let b = BigInt::from_le_bytes(other.array.as_slice(), secpk1_fq); + let a = BigInt::from_le_bytes(self.array.as_slice(), bn254_fr); + let b = BigInt::from_le_bytes(other.array.as_slice(), bn254_fr); Bn254Fr { array: a.bigint_div(b).to_le_bytes() } @@ -287,8 +285,8 @@ impl BigField for Bn254Fq { impl Add for Bn254Fq { fn add(self: Self, other: Bn254Fq) -> Bn254Fq { - let a = BigInt::from_le_bytes(self.array.as_slice(), secpk1_fq); - let b = BigInt::from_le_bytes(other.array.as_slice(), secpk1_fq); + let a = BigInt::from_le_bytes(self.array.as_slice(), bn254_fq); + let b = BigInt::from_le_bytes(other.array.as_slice(), bn254_fq); Bn254Fq { array: a.bigint_add(b).to_le_bytes() } @@ -296,8 +294,8 @@ impl Add for Bn254Fq { } impl Sub for Bn254Fq { fn sub(self: Self, other: Bn254Fq) -> Bn254Fq { - let a = BigInt::from_le_bytes(self.array.as_slice(), secpk1_fq); - let b = BigInt::from_le_bytes(other.array.as_slice(), secpk1_fq); + let a = BigInt::from_le_bytes(self.array.as_slice(), bn254_fq); + let b = BigInt::from_le_bytes(other.array.as_slice(), bn254_fq); Bn254Fq { array: a.bigint_sub(b).to_le_bytes() } @@ -305,8 +303,8 @@ impl Sub for Bn254Fq { } impl Mul for Bn254Fq { fn mul(self: Self, other: Bn254Fq) -> Bn254Fq { - let a = BigInt::from_le_bytes(self.array.as_slice(), secpk1_fq); - let b = BigInt::from_le_bytes(other.array.as_slice(), secpk1_fq); + let a = BigInt::from_le_bytes(self.array.as_slice(), bn254_fq); + let b = BigInt::from_le_bytes(other.array.as_slice(), bn254_fq); Bn254Fq { array: a.bigint_mul(b).to_le_bytes() } @@ -314,8 +312,8 @@ impl Mul for Bn254Fq { } impl Div for Bn254Fq { fn div(self: Self, other: Bn254Fq) -> Bn254Fq { - let a = BigInt::from_le_bytes(self.array.as_slice(), secpk1_fq); - let b = BigInt::from_le_bytes(other.array.as_slice(), secpk1_fq); + let a = BigInt::from_le_bytes(self.array.as_slice(), bn254_fq); + let b = BigInt::from_le_bytes(other.array.as_slice(), bn254_fq); Bn254Fq { array: a.bigint_div(b).to_le_bytes() } @@ -356,8 +354,8 @@ impl BigField for Secpr1Fq { impl Add for Secpr1Fq { fn add(self: Self, other: Secpr1Fq) -> Secpr1Fq { - let a = BigInt::from_le_bytes(self.array.as_slice(), secpk1_fq); - let b = BigInt::from_le_bytes(other.array.as_slice(), secpk1_fq); + let a = BigInt::from_le_bytes(self.array.as_slice(), secpr1_fq); + let b = BigInt::from_le_bytes(other.array.as_slice(), secpr1_fq); Secpr1Fq { array: a.bigint_add(b).to_le_bytes() } @@ -365,8 +363,8 @@ impl Add for Secpr1Fq { } impl Sub for Secpr1Fq { fn sub(self: Self, other: Secpr1Fq) -> Secpr1Fq { - let a = BigInt::from_le_bytes(self.array.as_slice(), secpk1_fq); - let b = BigInt::from_le_bytes(other.array.as_slice(), secpk1_fq); + let a = BigInt::from_le_bytes(self.array.as_slice(), secpr1_fq); + let b = BigInt::from_le_bytes(other.array.as_slice(), secpr1_fq); Secpr1Fq { array: a.bigint_sub(b).to_le_bytes() } @@ -374,8 +372,8 @@ impl Sub for Secpr1Fq { } impl Mul for Secpr1Fq { fn mul(self: Self, other: Secpr1Fq) -> Secpr1Fq { - let a = BigInt::from_le_bytes(self.array.as_slice(), secpk1_fq); - let b = BigInt::from_le_bytes(other.array.as_slice(), secpk1_fq); + let a = BigInt::from_le_bytes(self.array.as_slice(), secpr1_fq); + let b = BigInt::from_le_bytes(other.array.as_slice(), secpr1_fq); Secpr1Fq { array: a.bigint_mul(b).to_le_bytes() } @@ -383,8 +381,8 @@ impl Mul for Secpr1Fq { } impl Div for Secpr1Fq { fn div(self: Self, other: Secpr1Fq) -> Secpr1Fq { - let a = BigInt::from_le_bytes(self.array.as_slice(), secpk1_fq); - let b = BigInt::from_le_bytes(other.array.as_slice(), secpk1_fq); + let a = BigInt::from_le_bytes(self.array.as_slice(), secpr1_fq); + let b = BigInt::from_le_bytes(other.array.as_slice(), secpr1_fq); Secpr1Fq { array: a.bigint_div(b).to_le_bytes() } @@ -425,8 +423,8 @@ impl BigField for Secpr1Fr { impl Add for Secpr1Fr { fn add(self: Self, other: Secpr1Fr) -> Secpr1Fr { - let a = BigInt::from_le_bytes(self.array.as_slice(), secpk1_fq); - let b = BigInt::from_le_bytes(other.array.as_slice(), secpk1_fq); + let a = BigInt::from_le_bytes(self.array.as_slice(), secpr1_fr); + let b = BigInt::from_le_bytes(other.array.as_slice(), secpr1_fr); Secpr1Fr { array: a.bigint_add(b).to_le_bytes() } @@ -434,8 +432,8 @@ impl Add for Secpr1Fr { } impl Sub for Secpr1Fr { fn sub(self: Self, other: Secpr1Fr) -> Secpr1Fr { - let a = BigInt::from_le_bytes(self.array.as_slice(), secpk1_fq); - let b = BigInt::from_le_bytes(other.array.as_slice(), secpk1_fq); + let a = BigInt::from_le_bytes(self.array.as_slice(), secpr1_fr); + let b = BigInt::from_le_bytes(other.array.as_slice(), secpr1_fr); Secpr1Fr { array: a.bigint_sub(b).to_le_bytes() } @@ -443,8 +441,8 @@ impl Sub for Secpr1Fr { } impl Mul for Secpr1Fr { fn mul(self: Self, other: Secpr1Fr) -> Secpr1Fr { - let a = BigInt::from_le_bytes(self.array.as_slice(), secpk1_fq); - let b = BigInt::from_le_bytes(other.array.as_slice(), secpk1_fq); + let a = BigInt::from_le_bytes(self.array.as_slice(), secpr1_fr); + let b = BigInt::from_le_bytes(other.array.as_slice(), secpr1_fr); Secpr1Fr { array: a.bigint_mul(b).to_le_bytes() } @@ -452,8 +450,8 @@ impl Mul for Secpr1Fr { } impl Div for Secpr1Fr { fn div(self: Self, other: Secpr1Fr) -> Secpr1Fr { - let a = BigInt::from_le_bytes(self.array.as_slice(), secpk1_fq); - let b = BigInt::from_le_bytes(other.array.as_slice(), secpk1_fq); + let a = BigInt::from_le_bytes(self.array.as_slice(), secpr1_fr); + let b = BigInt::from_le_bytes(other.array.as_slice(), secpr1_fr); Secpr1Fr { array: a.bigint_div(b).to_le_bytes() } diff --git a/noir/noir-repo/test_programs/execution_success/bigint/src/main.nr b/noir/noir-repo/test_programs/execution_success/bigint/src/main.nr index 5645e4e9e1b..c454c2b66cd 100644 --- a/noir/noir-repo/test_programs/execution_success/bigint/src/main.nr +++ b/noir/noir-repo/test_programs/execution_success/bigint/src/main.nr @@ -13,7 +13,7 @@ fn main(mut x: [u8; 5], y: [u8; 5]) { let a_field = dep::std::field::bytes32_to_field(a_be_bytes); let b_field = dep::std::field::bytes32_to_field(b_be_bytes); - // Regression for #4682 + // Regression for issue #4682 let c = if x[0] != 0 { test_unconstrained1(a, b) } else { @@ -27,7 +27,7 @@ fn main(mut x: [u8; 5], y: [u8; 5]) { assert(a_bytes[i] == x[i]); assert(b_bytes[i] == y[i]); } - //Regression for issue #4578 + // Regression for issue #4578 let d = a * b; assert(d / b == a); @@ -40,6 +40,22 @@ fn main(mut x: [u8; 5], y: [u8; 5]) { let d1 = bigint::Secpk1Fq::from_le_bytes_32(result); assert(d1 == d); big_int_example(x[0], x[1]); + + // Regression for issue #4882 + let num_b:[u8;32] = [ + 0, 0, 0, 240, 147, 245, 225, 67, 145, 112, 185, 121, 72, 232, 51, 40, 93, 88, 129, 129, 182, 69, 80, 184, 41, 160, 49, 225, 114, 78, 100, 48 + ]; + let num2_b:[u8;7] = [126, 193, 45, 39, 188, 84, 11]; + let num = bigint::Bn254Fr::from_le_bytes(num_b.as_slice()); + let num2 = bigint::Bn254Fr::from_le_bytes(num2_b.as_slice()); + + let ret_b:[u8;32] = [ + 131, 62, 210, 200, 215, 160, 214, 67, 145, 112, 185, 121, 72, 232, 51, 40, 93, 88, 129, 129, 182, 69, 80, 184, 41, 160, 49, 225, 114, 78, 100, 48 + ]; + let ret = bigint::Bn254Fr::from_le_bytes(ret_b.as_slice()); + assert(ret == num.mul(num2)); + let div = num.div(num2); + assert(div.mul(num2) == num); } fn test_unconstrained1(a: Secpk1Fq, b: Secpk1Fq) -> Secpk1Fq { diff --git a/noir/noir-repo/tooling/nargo_cli/src/cli/info_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/info_cmd.rs index 67825362f92..3695fb57d31 100644 --- a/noir/noir-repo/tooling/nargo_cli/src/cli/info_cmd.rs +++ b/noir/noir-repo/tooling/nargo_cli/src/cli/info_cmd.rs @@ -228,7 +228,7 @@ struct InfoReport { #[derive(Debug, Serialize)] struct ProgramInfo { - name: String, + package_name: String, #[serde(skip)] expression_width: ExpressionWidth, functions: Vec, @@ -238,7 +238,7 @@ impl From for Vec { fn from(program_info: ProgramInfo) -> Self { vecmap(program_info.functions, |function| { row![ - Fm->format!("{}", program_info.name), + Fm->format!("{}", program_info.package_name), Fc->format!("{}", function.name), format!("{:?}", program_info.expression_width), Fc->format!("{}", function.acir_opcodes), @@ -302,7 +302,7 @@ fn count_opcodes_and_gates_in_program( }) .collect::>()?; - Ok(ProgramInfo { name: package.name.to_string(), expression_width, functions }) + Ok(ProgramInfo { package_name: package.name.to_string(), expression_width, functions }) } fn count_opcodes_and_gates_in_contract( diff --git a/noir/noir-repo/tooling/nargo_fmt/src/rewrite/expr.rs b/noir/noir-repo/tooling/nargo_fmt/src/rewrite/expr.rs index e4616c99aaa..6b7dca6c5c7 100644 --- a/noir/noir-repo/tooling/nargo_fmt/src/rewrite/expr.rs +++ b/noir/noir-repo/tooling/nargo_fmt/src/rewrite/expr.rs @@ -159,6 +159,9 @@ pub(crate) fn rewrite( } ExpressionKind::Lambda(_) | ExpressionKind::Variable(_) => visitor.slice(span).to_string(), ExpressionKind::Quote(block) => format!("quote {}", rewrite_block(visitor, block, span)), + ExpressionKind::Comptime(block) => { + format!("comptime {}", rewrite_block(visitor, block, span)) + } ExpressionKind::Error => unreachable!(), } } diff --git a/noir/noir-repo/tooling/noirc_abi_wasm/build.sh b/noir/noir-repo/tooling/noirc_abi_wasm/build.sh index 58724dee02c..ee93413ab85 100755 --- a/noir/noir-repo/tooling/noirc_abi_wasm/build.sh +++ b/noir/noir-repo/tooling/noirc_abi_wasm/build.sh @@ -25,6 +25,7 @@ function run_if_available { require_command jq require_command cargo require_command wasm-bindgen +# require_command wasm-opt self_path=$(dirname "$(readlink -f "$0")") pname=$(cargo read-manifest | jq -r '.name')