diff --git a/.noir-sync-commit b/.noir-sync-commit index 19e9a0d3012..78cfb1ccf97 100644 --- a/.noir-sync-commit +++ b/.noir-sync-commit @@ -1 +1 @@ -0cf2e2a1b8d247bed03ba5b7b1be5cd30f0d51b2 +1ec9cdc7013e867db3672d27e3a6104e4b7e7eef \ No newline at end of file diff --git a/avm-transpiler/Cargo.lock b/avm-transpiler/Cargo.lock index e922fb18971..7e530d6cc7b 100644 --- a/avm-transpiler/Cargo.lock +++ b/avm-transpiler/Cargo.lock @@ -159,10 +159,6 @@ dependencies = [ "windows-sys", ] -[[package]] -name = "arena" -version = "0.28.0" - [[package]] name = "ark-bn254" version = "0.4.0" @@ -1211,6 +1207,10 @@ dependencies = [ "toml", ] +[[package]] +name = "noirc_arena" +version = "0.28.0" + [[package]] name = "noirc_driver" version = "0.28.0" @@ -1272,13 +1272,13 @@ name = "noirc_frontend" version = "0.28.0" dependencies = [ "acvm", - "arena", "chumsky", "fm", "im", "iter-extended", "lalrpop", "lalrpop-util", + "noirc_arena", "noirc_errors", "noirc_printable_type", "petgraph", diff --git a/noir/Earthfile b/noir/Earthfile index 9e1f7610b82..63f37774607 100644 --- a/noir/Earthfile +++ b/noir/Earthfile @@ -12,6 +12,7 @@ nargo: noir-repo/noir_stdlib \ noir-repo/tooling \ noir-repo/test_programs \ + noir-repo/utils \ noir-repo/Cargo.lock \ noir-repo/Cargo.toml \ noir-repo @@ -49,6 +50,7 @@ packages: noir-repo/scripts \ noir-repo/test_programs \ noir-repo/tooling \ + noir-repo/utils \ noir-repo/Cargo.lock \ noir-repo/.yarnrc.yml \ noir-repo/.yarn \ diff --git a/noir/noir-repo/Cargo.lock b/noir/noir-repo/Cargo.lock index 377e3339d7e..2e31dee9a60 100644 --- a/noir/noir-repo/Cargo.lock +++ b/noir/noir-repo/Cargo.lock @@ -233,10 +233,6 @@ version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" -[[package]] -name = "arena" -version = "0.28.0" - [[package]] name = "ark-bls12-381" version = "0.4.0" @@ -3100,6 +3096,10 @@ dependencies = [ "wasm-bindgen-test", ] +[[package]] +name = "noirc_arena" +version = "0.28.0" + [[package]] name = "noirc_driver" version = "0.28.0" @@ -3161,7 +3161,6 @@ name = "noirc_frontend" version = "0.28.0" dependencies = [ "acvm", - "arena", "base64 0.21.2", "chumsky", "fm", @@ -3169,6 +3168,7 @@ dependencies = [ "iter-extended", "lalrpop", "lalrpop-util", + "noirc_arena", "noirc_errors", "noirc_printable_type", "petgraph", diff --git a/noir/noir-repo/Cargo.toml b/noir/noir-repo/Cargo.toml index 8911f6bfccb..6fe7f099e82 100644 --- a/noir/noir-repo/Cargo.toml +++ b/noir/noir-repo/Cargo.toml @@ -4,6 +4,7 @@ members = [ # Aztec Macro crate for metaprogramming "aztec_macros", # Compiler crates + "compiler/noirc_arena", "compiler/noirc_evaluator", "compiler/noirc_frontend", "compiler/noirc_errors", @@ -11,10 +12,7 @@ members = [ "compiler/noirc_printable_type", "compiler/fm", "compiler/wasm", - # Utility crates used by the Noir compiler - "compiler/utils/arena", - "compiler/utils/iter-extended", - # Crates related to tooling built ontop of the Noir compiler + # Crates related to tooling built on top of the Noir compiler "tooling/backend_interface", "tooling/bb_abstraction_leaks", "tooling/lsp", @@ -35,6 +33,8 @@ members = [ "acvm-repo/brillig_vm", "acvm-repo/blackbox_solver", "acvm-repo/bn254_blackbox_solver", + # Utility crates + "utils/iter-extended", ] default-members = ["tooling/nargo_cli", "tooling/acvm_cli"] resolver = "2" @@ -61,9 +61,8 @@ acvm_blackbox_solver = { version = "0.44.0", path = "acvm-repo/blackbox_solver", bn254_blackbox_solver = { version = "0.44.0", path = "acvm-repo/bn254_blackbox_solver", default-features = false } # Noir compiler workspace dependencies -arena = { path = "compiler/utils/arena" } fm = { path = "compiler/fm" } -iter-extended = { path = "compiler/utils/iter-extended" } +noirc_arena = { path = "compiler/noirc_arena" } noirc_driver = { path = "compiler/noirc_driver" } noirc_errors = { path = "compiler/noirc_errors" } noirc_evaluator = { path = "compiler/noirc_evaluator" } @@ -80,6 +79,9 @@ noirc_abi = { path = "tooling/noirc_abi" } bb_abstraction_leaks = { path = "tooling/bb_abstraction_leaks" } acvm_cli = { path = "tooling/acvm_cli" } +# Misc utils crates +iter-extended = { path = "utils/iter-extended" } + # LSP async-lsp = { version = "0.1.0", default-features = false } lsp-types = "0.94.1" diff --git a/noir/noir-repo/acvm-repo/acvm_js/build.sh b/noir/noir-repo/acvm-repo/acvm_js/build.sh index ee93413ab85..c07d2d8a4c1 100755 --- a/noir/noir-repo/acvm-repo/acvm_js/build.sh +++ b/noir/noir-repo/acvm-repo/acvm_js/build.sh @@ -25,7 +25,7 @@ function run_if_available { require_command jq require_command cargo require_command wasm-bindgen -# require_command wasm-opt +#require_command wasm-opt self_path=$(dirname "$(readlink -f "$0")") pname=$(cargo read-manifest | jq -r '.name') diff --git a/noir/noir-repo/compiler/utils/arena/Cargo.toml b/noir/noir-repo/compiler/noirc_arena/Cargo.toml similarity index 86% rename from noir/noir-repo/compiler/utils/arena/Cargo.toml rename to noir/noir-repo/compiler/noirc_arena/Cargo.toml index f6bd764ee62..b94f997b7b9 100644 --- a/noir/noir-repo/compiler/utils/arena/Cargo.toml +++ b/noir/noir-repo/compiler/noirc_arena/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "arena" +name = "noirc_arena" version.workspace = true authors.workspace = true edition.workspace = true diff --git a/noir/noir-repo/compiler/utils/arena/src/lib.rs b/noir/noir-repo/compiler/noirc_arena/src/lib.rs similarity index 100% rename from noir/noir-repo/compiler/utils/arena/src/lib.rs rename to noir/noir-repo/compiler/noirc_arena/src/lib.rs diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa.rs index 92461e1a1b1..7a7ee24a670 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa.rs @@ -9,10 +9,7 @@ use std::collections::{BTreeMap, BTreeSet}; -use crate::{ - brillig::Brillig, - errors::{RuntimeError, SsaReport}, -}; +use crate::errors::{RuntimeError, SsaReport}; use acvm::acir::{ circuit::{ brillig::BrilligBytecode, Circuit, ExpressionWidth, Program as AcirProgram, PublicInputs, @@ -334,10 +331,6 @@ impl SsaBuilder { Ok(self.print(msg)) } - fn to_brillig(&self, print_brillig_trace: bool) -> Brillig { - self.ssa.to_brillig(print_brillig_trace) - } - fn print(self, msg: &str) -> Self { if self.print_ssa_passes { println!("{msg}\n{}", self.ssa); diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs index 1d3bc3fce57..c084ba37fee 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs @@ -419,55 +419,6 @@ impl GeneratedAcir { Ok(limb_witnesses) } - /// Returns an expression which represents `lhs * rhs` - /// - /// If one has multiplicative term and the other is of degree one or more, - /// the function creates [intermediate variables][`Witness`] accordingly. - /// There are two cases where we can optimize the multiplication between two expressions: - /// 1. If the sum of the degrees of both expressions is at most 2, then we can just multiply them - /// as each term in the result will be degree-2. - /// 2. If one expression is a constant, then we can just multiply the constant with the other expression - /// - /// (1) is because an [`Expression`] can hold at most a degree-2 univariate polynomial - /// which is what you get when you multiply two degree-1 univariate polynomials. - pub(crate) fn mul_with_witness(&mut self, lhs: &Expression, rhs: &Expression) -> Expression { - use std::borrow::Cow; - let lhs_is_linear = lhs.is_linear(); - let rhs_is_linear = rhs.is_linear(); - - // Case 1: The sum of the degrees of both expressions is at most 2. - // - // If one of the expressions is constant then it does not increase the degree when multiplying by another expression. - // If both of the expressions are linear (degree <=1) then the product will be at most degree 2. - let both_are_linear = lhs_is_linear && rhs_is_linear; - let either_is_const = lhs.is_const() || rhs.is_const(); - if both_are_linear || either_is_const { - return (lhs * rhs).expect("Both expressions are degree <= 1"); - } - - // Case 2: One or both of the sides needs to be reduced to a degree-1 univariate polynomial - let lhs_reduced = if lhs_is_linear { - Cow::Borrowed(lhs) - } else { - Cow::Owned(self.get_or_create_witness(lhs).into()) - }; - - // If the lhs and rhs are the same, then we do not need to reduce - // rhs, we only need to square the lhs. - if lhs == rhs { - return (&*lhs_reduced * &*lhs_reduced) - .expect("Both expressions are reduced to be degree <= 1"); - }; - - let rhs_reduced = if rhs_is_linear { - Cow::Borrowed(rhs) - } else { - Cow::Owned(self.get_or_create_witness(rhs).into()) - }; - - (&*lhs_reduced * &*rhs_reduced).expect("Both expressions are reduced to be degree <= 1") - } - /// Adds an inversion brillig opcode. /// /// This code will invert `expr` without applying constraints diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs index 80dcb5db328..c5e4e88862f 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs @@ -28,8 +28,8 @@ use crate::brillig::brillig_ir::artifact::{BrilligParameter, GeneratedBrillig}; use crate::brillig::brillig_ir::BrilligContext; use crate::brillig::{brillig_gen::brillig_fn::FunctionContext as BrilligFunctionContext, Brillig}; use crate::errors::{InternalError, InternalWarning, RuntimeError, SsaReport}; -use crate::ssa::ir::function::InlineType; pub(crate) use acir_ir::generated_acir::GeneratedAcir; +use noirc_frontend::monomorphization::ast::InlineType; use acvm::acir::circuit::brillig::BrilligBytecode; use acvm::acir::circuit::{AssertionPayload, OpcodeLocation}; @@ -389,12 +389,12 @@ impl<'a> Context<'a> { match function.runtime() { RuntimeType::Acir(inline_type) => { match inline_type { - InlineType::Fold => {} InlineType::Inline => { if function.id() != ssa.main_id { panic!("ACIR function should have been inlined earlier if not marked otherwise"); } } + InlineType::Fold | InlineType::Never => {} } // We only want to convert entry point functions. This being `main` and those marked with `InlineType::Fold` Ok(Some(self.convert_acir_main(function, ssa, brillig)?)) @@ -2629,25 +2629,22 @@ mod test { }, FieldElement, }; + use noirc_frontend::monomorphization::ast::InlineType; use crate::{ brillig::Brillig, ssa::{ acir_gen::acir_ir::generated_acir::BrilligStdlibFunc, function_builder::FunctionBuilder, - ir::{ - function::{FunctionId, InlineType}, - instruction::BinaryOp, - map::Id, - types::Type, - }, + ir::{function::FunctionId, instruction::BinaryOp, map::Id, types::Type}, }, }; fn build_basic_foo_with_return( builder: &mut FunctionBuilder, foo_id: FunctionId, - is_brillig_func: bool, + // `InlineType` can only exist on ACIR functions, so if the option is `None` we should generate a Brillig function + inline_type: Option, ) { // fn foo f1 { // b0(v0: Field, v1: Field): @@ -2655,10 +2652,10 @@ mod test { // constrain v2 == u1 0 // return v0 // } - if is_brillig_func { - builder.new_brillig_function("foo".into(), foo_id); + if let Some(inline_type) = inline_type { + builder.new_function("foo".into(), foo_id, inline_type); } else { - builder.new_function("foo".into(), foo_id, InlineType::Fold); + builder.new_brillig_function("foo".into(), foo_id); } let foo_v0 = builder.add_parameter(Type::field()); let foo_v1 = builder.add_parameter(Type::field()); @@ -2669,8 +2666,25 @@ mod test { builder.terminate_with_return(vec![foo_v0]); } + /// Check that each `InlineType` which prevents inlining functions generates code in the same manner + #[test] + fn basic_calls_fold() { + basic_call_with_outputs_assert(InlineType::Fold); + call_output_as_next_call_input(InlineType::Fold); + basic_nested_call(InlineType::Fold); + + call_output_as_next_call_input(InlineType::Never); + basic_nested_call(InlineType::Never); + basic_call_with_outputs_assert(InlineType::Never); + } + #[test] - fn basic_call_with_outputs_assert() { + #[should_panic] + fn call_without_inline_attribute() { + basic_call_with_outputs_assert(InlineType::Inline); + } + + fn basic_call_with_outputs_assert(inline_type: InlineType) { // acir(inline) fn main f0 { // b0(v0: Field, v1: Field): // v2 = call f1(v0, v1) @@ -2698,7 +2712,7 @@ mod test { builder.insert_constrain(main_call1_results[0], main_call2_results[0], None); builder.terminate_with_return(vec![]); - build_basic_foo_with_return(&mut builder, foo_id, false); + build_basic_foo_with_return(&mut builder, foo_id, Some(inline_type)); let ssa = builder.finish(); @@ -2764,8 +2778,7 @@ mod test { } } - #[test] - fn call_output_as_next_call_input() { + fn call_output_as_next_call_input(inline_type: InlineType) { // acir(inline) fn main f0 { // b0(v0: Field, v1: Field): // v3 = call f1(v0, v1) @@ -2794,7 +2807,7 @@ mod test { builder.insert_constrain(main_call1_results[0], main_call2_results[0], None); builder.terminate_with_return(vec![]); - build_basic_foo_with_return(&mut builder, foo_id, false); + build_basic_foo_with_return(&mut builder, foo_id, Some(inline_type)); let ssa = builder.finish(); @@ -2813,8 +2826,7 @@ mod test { check_call_opcode(&main_opcodes[1], 1, vec![Witness(2), Witness(1)], vec![Witness(3)]); } - #[test] - fn basic_nested_call() { + fn basic_nested_call(inline_type: InlineType) { // SSA for the following Noir program: // fn main(x: Field, y: pub Field) { // let z = func_with_nested_foo_call(x, y); @@ -2870,7 +2882,7 @@ mod test { builder.new_function( "func_with_nested_foo_call".into(), func_with_nested_foo_call_id, - InlineType::Fold, + inline_type, ); let func_with_nested_call_v0 = builder.add_parameter(Type::field()); let func_with_nested_call_v1 = builder.add_parameter(Type::field()); @@ -2885,7 +2897,7 @@ mod test { .to_vec(); builder.terminate_with_return(vec![foo_call[0]]); - build_basic_foo_with_return(&mut builder, foo_id, false); + build_basic_foo_with_return(&mut builder, foo_id, Some(inline_type)); let ssa = builder.finish(); @@ -2996,8 +3008,8 @@ mod test { builder.insert_call(bar, vec![main_v0, main_v1], vec![Type::field()]).to_vec(); builder.terminate_with_return(vec![]); - build_basic_foo_with_return(&mut builder, foo_id, true); - build_basic_foo_with_return(&mut builder, bar_id, true); + build_basic_foo_with_return(&mut builder, foo_id, None); + build_basic_foo_with_return(&mut builder, bar_id, None); let ssa = builder.finish(); let brillig = ssa.to_brillig(false); @@ -3124,7 +3136,7 @@ mod test { builder.terminate_with_return(vec![]); - build_basic_foo_with_return(&mut builder, foo_id, true); + build_basic_foo_with_return(&mut builder, foo_id, None); let ssa = builder.finish(); // We need to generate Brillig artifacts for the regular Brillig function and pass them to the ACIR generation pass. @@ -3210,8 +3222,10 @@ mod test { builder.terminate_with_return(vec![]); - build_basic_foo_with_return(&mut builder, foo_id, true); - build_basic_foo_with_return(&mut builder, bar_id, false); + // Build a Brillig function + build_basic_foo_with_return(&mut builder, foo_id, None); + // Build an ACIR function which has the same logic as the Brillig function above + build_basic_foo_with_return(&mut builder, bar_id, Some(InlineType::Fold)); let ssa = builder.finish(); // We need to generate Brillig artifacts for the regular Brillig function and pass them to the ACIR generation pass. @@ -3295,18 +3309,15 @@ mod test { // This check right now expects to only call one Brillig function. let mut num_normal_brillig_calls = 0; for (i, opcode) in opcodes.iter().enumerate() { - match opcode { - Opcode::BrilligCall { id, .. } => { - if brillig_stdlib_function_locations.get(&OpcodeLocation::Acir(i)).is_some() { - // We should have already checked Brillig stdlib functions and only want to check normal Brillig calls here - continue; - } - // We only generate one normal Brillig call so we should expect a function ID of `0` - let expected_id = 0u32; - assert_eq!(*id, expected_id, "Expected an id of {expected_id} but got {id}"); - num_normal_brillig_calls += 1; + if let Opcode::BrilligCall { id, .. } = opcode { + if brillig_stdlib_function_locations.get(&OpcodeLocation::Acir(i)).is_some() { + // We should have already checked Brillig stdlib functions and only want to check normal Brillig calls here + continue; } - _ => {} + // We only generate one normal Brillig call so we should expect a function ID of `0` + let expected_id = 0u32; + assert_eq!(*id, expected_id, "Expected an id of {expected_id} but got {id}"); + num_normal_brillig_calls += 1; } } diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs index e149769f786..c0aa86c89bb 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs @@ -4,6 +4,7 @@ use std::{borrow::Cow, collections::BTreeMap, rc::Rc}; use acvm::FieldElement; use noirc_errors::Location; +use noirc_frontend::monomorphization::ast::InlineType; use crate::ssa::ir::{ basic_block::BasicBlockId, @@ -17,7 +18,7 @@ use super::{ ir::{ basic_block::BasicBlock, dfg::{CallStack, InsertInstructionResult}, - function::{InlineType, RuntimeType}, + function::RuntimeType, instruction::{ConstrainError, ErrorSelector, ErrorType, InstructionId, Intrinsic}, }, ssa_gen::Ssa, diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/function.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/function.rs index 011bee36661..057786bf5ec 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/function.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/function.rs @@ -1,6 +1,7 @@ use std::collections::BTreeSet; use iter_extended::vecmap; +use noirc_frontend::monomorphization::ast::InlineType; use super::basic_block::BasicBlockId; use super::dfg::DataFlowGraph; @@ -17,18 +18,6 @@ pub(crate) enum RuntimeType { Brillig, } -/// Represents how a RuntimeType::Acir function should be inlined. -/// This type is only relevant for ACIR functions as we do not inline any Brillig functions -#[derive(Default, Clone, Copy, PartialEq, Eq, Debug, Hash)] -pub(crate) enum InlineType { - /// The most basic entry point can expect all its functions to be inlined. - /// All function calls are expected to be inlined into a single ACIR. - #[default] - Inline, - /// Functions marked as foldable will not be inlined and compiled separately into ACIR - Fold, -} - impl RuntimeType { /// Returns whether the runtime type represents an entry point. /// We return `false` for InlineType::Inline on default, which is true @@ -36,10 +25,7 @@ impl RuntimeType { /// handling in any places where this function determines logic. pub(crate) fn is_entry_point(&self) -> bool { match self { - RuntimeType::Acir(inline_type) => match inline_type { - InlineType::Inline => false, - InlineType::Fold => true, - }, + RuntimeType::Acir(inline_type) => inline_type.is_entry_point(), RuntimeType::Brillig => true, } } @@ -163,15 +149,6 @@ impl std::fmt::Display for RuntimeType { } } -impl std::fmt::Display for InlineType { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - InlineType::Inline => write!(f, "inline"), - InlineType::Fold => write!(f, "fold"), - } - } -} - /// FunctionId is a reference for a function /// /// This Id is how each function refers to other functions diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/inlining.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/inlining.rs index ead3cac071c..0b78d47fbb1 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/inlining.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/inlining.rs @@ -517,12 +517,12 @@ impl<'function> PerFunctionContext<'function> { #[cfg(test)] mod test { use acvm::FieldElement; + use noirc_frontend::monomorphization::ast::InlineType; use crate::ssa::{ function_builder::FunctionBuilder, ir::{ basic_block::BasicBlockId, - function::InlineType, instruction::{BinaryOp, Intrinsic, TerminatorInstruction}, map::Id, types::Type, diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs index 276a8247cea..f2cc2ba53cc 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs @@ -11,9 +11,8 @@ use noirc_frontend::monomorphization::ast::{FuncId, Program}; use crate::errors::RuntimeError; use crate::ssa::function_builder::FunctionBuilder; use crate::ssa::ir::basic_block::BasicBlockId; -use crate::ssa::ir::dfg::DataFlowGraph; +use crate::ssa::ir::function::FunctionId as IrFunctionId; use crate::ssa::ir::function::{Function, RuntimeType}; -use crate::ssa::ir::function::{FunctionId as IrFunctionId, InlineType}; use crate::ssa::ir::instruction::BinaryOp; use crate::ssa::ir::instruction::Instruction; use crate::ssa::ir::map::AtomicCounter; @@ -126,8 +125,7 @@ impl<'a> FunctionContext<'a> { if func.unconstrained { self.builder.new_brillig_function(func.name.clone(), id); } else { - let inline_type = if func.should_fold { InlineType::Fold } else { InlineType::Inline }; - self.builder.new_function(func.name.clone(), id, inline_type); + self.builder.new_function(func.name.clone(), id, func.inline_type); } self.add_parameters_to_scope(&func.parameters); } @@ -1005,72 +1003,6 @@ fn operator_requires_swapped_operands(op: BinaryOpKind) -> bool { matches!(op, Greater | LessEqual) } -/// If the operation requires its result to be truncated because it is an integer, the maximum -/// number of bits that result may occupy is returned. -fn operator_result_max_bit_size_to_truncate( - op: BinaryOpKind, - lhs: ValueId, - rhs: ValueId, - dfg: &DataFlowGraph, -) -> Option { - let lhs_type = dfg.type_of_value(lhs); - let rhs_type = dfg.type_of_value(rhs); - - let get_bit_size = |typ| match typ { - Type::Numeric(NumericType::Signed { bit_size } | NumericType::Unsigned { bit_size }) => { - Some(bit_size) - } - _ => None, - }; - - let lhs_bit_size = get_bit_size(lhs_type)?; - let rhs_bit_size = get_bit_size(rhs_type)?; - use BinaryOpKind::*; - match op { - Add => Some(std::cmp::max(lhs_bit_size, rhs_bit_size) + 1), - Subtract => Some(std::cmp::max(lhs_bit_size, rhs_bit_size) + 1), - Multiply => { - if lhs_bit_size == 1 || rhs_bit_size == 1 { - // Truncation is unnecessary as multiplication by a boolean value cannot cause an overflow. - None - } else { - Some(lhs_bit_size + rhs_bit_size) - } - } - - ShiftLeft => { - if let Some(rhs_constant) = dfg.get_numeric_constant(rhs) { - // Happy case is that we know precisely by how many bits the the integer will - // increase: lhs_bit_size + rhs - return Some(lhs_bit_size + (rhs_constant.to_u128() as u32)); - } - // Unhappy case is that we don't yet know the rhs value, (even though it will - // eventually have to resolve to a constant). The best we can is assume the value of - // rhs to be the maximum value of it's numeric type. If that turns out to be larger - // than the native field's bit size, we full back to using that. - - // The formula for calculating the max bit size of a left shift is: - // lhs_bit_size + 2^{rhs_bit_size} - 1 - // Inferring the max bit size of left shift from its operands can result in huge - // number, that might not only be larger than the native field's max bit size, but - // furthermore might not be representable as a u32. Hence we use overflow checks and - // fallback to the native field's max bits. - let field_max_bits = FieldElement::max_num_bits(); - let (rhs_bit_size_pow_2, overflows) = 2_u32.overflowing_pow(rhs_bit_size); - if overflows { - return Some(field_max_bits); - } - let (max_bits_plus_1, overflows) = rhs_bit_size_pow_2.overflowing_add(lhs_bit_size); - if overflows { - return Some(field_max_bits); - } - let max_bit_size = std::cmp::min(max_bits_plus_1 - 1, field_max_bits); - Some(max_bit_size) - } - _ => None, - } -} - /// Converts the given operator to the appropriate BinaryOp. /// Take care when using this to insert a binary instruction: this requires /// checking operator_requires_not and operator_requires_swapped_operands diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs index 8de09d4309b..c121ac19ff9 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs @@ -13,10 +13,7 @@ use noirc_frontend::monomorphization::ast::{self, Expression, Program}; use crate::{ errors::RuntimeError, - ssa::{ - function_builder::data_bus::DataBusBuilder, - ir::{function::InlineType, instruction::Intrinsic}, - }, + ssa::{function_builder::data_bus::DataBusBuilder, ir::instruction::Intrinsic}, }; use self::{ @@ -61,9 +58,7 @@ pub(crate) fn generate_ssa( if force_brillig_runtime || main.unconstrained { RuntimeType::Brillig } else { - let main_inline_type = - if main.should_fold { InlineType::Fold } else { InlineType::Inline }; - RuntimeType::Acir(main_inline_type) + RuntimeType::Acir(main.inline_type) }, &context, ); diff --git a/noir/noir-repo/compiler/noirc_frontend/Cargo.toml b/noir/noir-repo/compiler/noirc_frontend/Cargo.toml index 84c9393fa37..0430d214d53 100644 --- a/noir/noir-repo/compiler/noirc_frontend/Cargo.toml +++ b/noir/noir-repo/compiler/noirc_frontend/Cargo.toml @@ -10,10 +10,10 @@ license.workspace = true [dependencies] acvm.workspace = true +noirc_arena.workspace = true noirc_errors.workspace = true noirc_printable_type.workspace = true fm.workspace = true -arena.workspace = true iter-extended.workspace = true chumsky.workspace = true thiserror.workspace = true diff --git a/noir/noir-repo/compiler/noirc_frontend/src/ast/function.rs b/noir/noir-repo/compiler/noirc_frontend/src/ast/function.rs index 9816218c5f7..9115178671e 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/ast/function.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/ast/function.rs @@ -109,6 +109,7 @@ impl From for NoirFunction { Some(FunctionAttribute::Oracle(_)) => FunctionKind::Oracle, Some(FunctionAttribute::Recursive) => FunctionKind::Recursive, Some(FunctionAttribute::Fold) => FunctionKind::Normal, + Some(FunctionAttribute::Inline(_)) => FunctionKind::Normal, None => FunctionKind::Normal, }; 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 index 67d9a006b22..8de444252ab 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/errors.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/errors.rs @@ -1,11 +1,11 @@ -use crate::Type; +use crate::{hir::def_collector::dc_crate::CompilationError, Type}; use acvm::FieldElement; -use noirc_errors::Location; +use noirc_errors::{CustomDiagnostic, Location}; use super::value::Value; /// The possible errors that can halt the interpreter. -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum InterpreterError { ArgumentCountMismatch { expected: usize, actual: usize, call_location: Location }, TypeMismatch { expected: Type, value: Value, location: Location }, @@ -16,7 +16,7 @@ pub enum InterpreterError { NonBoolUsedInIf { value: Value, location: Location }, NonBoolUsedInConstrain { value: Value, location: Location }, FailingConstraint { message: Option, location: Location }, - NoMethodFound { object: Value, typ: Type, location: Location }, + NoMethodFound { name: String, typ: Type, location: Location }, NonIntegerUsedInLoop { value: Value, location: Location }, NonPointerDereferenced { value: Value, location: Location }, NonTupleOrStructInMemberAccess { value: Value, location: Location }, @@ -51,3 +51,221 @@ pub enum InterpreterError { #[allow(unused)] pub(super) type IResult = std::result::Result; + +impl InterpreterError { + pub fn into_compilation_error_pair(self) -> (CompilationError, fm::FileId) { + let location = self.get_location(); + (CompilationError::InterpreterError(self), location.file) + } + + pub fn get_location(&self) -> Location { + match self { + InterpreterError::ArgumentCountMismatch { call_location: location, .. } + | InterpreterError::TypeMismatch { location, .. } + | InterpreterError::NonComptimeVarReferenced { location, .. } + | InterpreterError::IntegerOutOfRangeForType { location, .. } + | InterpreterError::ErrorNodeEncountered { location, .. } + | InterpreterError::NonFunctionCalled { location, .. } + | InterpreterError::NonBoolUsedInIf { location, .. } + | InterpreterError::NonBoolUsedInConstrain { location, .. } + | InterpreterError::FailingConstraint { location, .. } + | InterpreterError::NoMethodFound { location, .. } + | InterpreterError::NonIntegerUsedInLoop { location, .. } + | InterpreterError::NonPointerDereferenced { location, .. } + | InterpreterError::NonTupleOrStructInMemberAccess { location, .. } + | InterpreterError::NonArrayIndexed { location, .. } + | InterpreterError::NonIntegerUsedAsIndex { location, .. } + | InterpreterError::NonIntegerIntegerLiteral { location, .. } + | InterpreterError::NonIntegerArrayLength { location, .. } + | InterpreterError::NonNumericCasted { location, .. } + | InterpreterError::IndexOutOfBounds { location, .. } + | InterpreterError::ExpectedStructToHaveField { location, .. } + | InterpreterError::TypeUnsupported { location, .. } + | InterpreterError::InvalidValueForUnary { location, .. } + | InterpreterError::InvalidValuesForBinary { location, .. } + | InterpreterError::CastToNonNumericType { location, .. } + | InterpreterError::QuoteInRuntimeCode { location, .. } + | InterpreterError::NonStructInConstructor { location, .. } + | InterpreterError::CannotInlineMacro { location, .. } + | InterpreterError::UnquoteFoundDuringEvaluation { location, .. } + | InterpreterError::Unimplemented { location, .. } + | InterpreterError::BreakNotInLoop { location, .. } + | InterpreterError::ContinueNotInLoop { location, .. } => *location, + InterpreterError::Break | InterpreterError::Continue => { + panic!("Tried to get the location of Break/Continue error!") + } + } + } +} + +impl From for CustomDiagnostic { + fn from(error: InterpreterError) -> Self { + match error { + InterpreterError::ArgumentCountMismatch { expected, actual, call_location } => { + let only = if expected > actual { "only " } else { "" }; + let plural = if expected == 1 { "" } else { "s" }; + let was_were = if actual == 1 { "was" } else { "were" }; + let msg = format!( + "Expected {expected} argument{plural}, but {only}{actual} {was_were} provided" + ); + + let few_many = if actual < expected { "few" } else { "many" }; + let secondary = format!("Too {few_many} arguments"); + CustomDiagnostic::simple_error(msg, secondary, call_location.span) + } + InterpreterError::TypeMismatch { expected, value, location } => { + let typ = value.get_type(); + let msg = format!("Expected `{expected}` but a value of type `{typ}` was given"); + CustomDiagnostic::simple_error(msg, String::new(), location.span) + } + InterpreterError::NonComptimeVarReferenced { name, location } => { + let msg = format!("Non-comptime variable `{name}` referenced in comptime code"); + let secondary = "Non-comptime variables can't be used in comptime code".to_string(); + CustomDiagnostic::simple_error(msg, secondary, location.span) + } + InterpreterError::IntegerOutOfRangeForType { value, typ, location } => { + let int = match value.try_into_u128() { + Some(int) => int.to_string(), + None => value.to_string(), + }; + let msg = format!("{int} is outside the range of the {typ} type"); + CustomDiagnostic::simple_error(msg, String::new(), location.span) + } + InterpreterError::ErrorNodeEncountered { location } => { + let msg = "Internal Compiler Error: Error node encountered".to_string(); + let secondary = "This is a bug, please report this if found!".to_string(); + CustomDiagnostic::simple_error(msg, secondary, location.span) + } + InterpreterError::NonFunctionCalled { value, location } => { + let msg = "Only functions may be called".to_string(); + let secondary = format!("Expression has type {}", value.get_type()); + CustomDiagnostic::simple_error(msg, secondary, location.span) + } + InterpreterError::NonBoolUsedInIf { value, location } => { + let msg = format!("Expected a `bool` but found `{}`", value.get_type()); + let secondary = "If conditions must be a boolean value".to_string(); + CustomDiagnostic::simple_error(msg, secondary, location.span) + } + InterpreterError::NonBoolUsedInConstrain { value, location } => { + let msg = format!("Expected a `bool` but found `{}`", value.get_type()); + CustomDiagnostic::simple_error(msg, String::new(), location.span) + } + InterpreterError::FailingConstraint { message, location } => { + let (primary, secondary) = match message { + Some(msg) => (format!("{msg:?}"), "Assertion failed".into()), + None => ("Assertion failed".into(), String::new()), + }; + CustomDiagnostic::simple_error(primary, secondary, location.span) + } + InterpreterError::NoMethodFound { name, typ, location } => { + let msg = format!("No method named `{name}` found for type `{typ}`"); + CustomDiagnostic::simple_error(msg, String::new(), location.span) + } + InterpreterError::NonIntegerUsedInLoop { value, location } => { + let typ = value.get_type(); + let msg = format!("Non-integer type `{typ}` used in for loop"); + let secondary = if matches!(typ.as_ref(), &Type::FieldElement) { + "`field` is not an integer type, try `u64` instead".to_string() + } else { + String::new() + }; + CustomDiagnostic::simple_error(msg, secondary, location.span) + } + InterpreterError::NonPointerDereferenced { value, location } => { + let typ = value.get_type(); + let msg = format!("Only references may be dereferenced, but found `{typ}`"); + CustomDiagnostic::simple_error(msg, String::new(), location.span) + } + InterpreterError::NonTupleOrStructInMemberAccess { value, location } => { + let msg = format!("The type `{}` has no fields to access", value.get_type()); + CustomDiagnostic::simple_error(msg, String::new(), location.span) + } + InterpreterError::NonArrayIndexed { value, location } => { + let msg = format!("Expected an array or slice but found a(n) {}", value.get_type()); + let secondary = "Only arrays or slices may be indexed".into(); + CustomDiagnostic::simple_error(msg, secondary, location.span) + } + InterpreterError::NonIntegerUsedAsIndex { value, location } => { + let msg = format!("Expected an integer but found a(n) {}", value.get_type()); + let secondary = + "Only integers may be indexed. Note that this excludes `field`s".into(); + CustomDiagnostic::simple_error(msg, secondary, location.span) + } + InterpreterError::NonIntegerIntegerLiteral { typ, location } => { + let msg = format!("This integer literal somehow has the type `{typ}`"); + let secondary = "This is likely a bug".into(); + CustomDiagnostic::simple_error(msg, secondary, location.span) + } + InterpreterError::NonIntegerArrayLength { typ, location } => { + let msg = format!("Non-integer array length: `{typ}`"); + let secondary = "Array lengths must be integers".into(); + CustomDiagnostic::simple_error(msg, secondary, location.span) + } + InterpreterError::NonNumericCasted { value, location } => { + let msg = "Only numeric types may be casted".into(); + let secondary = format!("`{}` is non-numeric", value.get_type()); + CustomDiagnostic::simple_error(msg, secondary, location.span) + } + InterpreterError::IndexOutOfBounds { index, length, location } => { + let msg = format!("{index} is out of bounds for the array of length {length}"); + CustomDiagnostic::simple_error(msg, String::new(), location.span) + } + InterpreterError::ExpectedStructToHaveField { value, field_name, location } => { + let typ = value.get_type(); + let msg = format!("The type `{typ}` has no field named `{field_name}`"); + CustomDiagnostic::simple_error(msg, String::new(), location.span) + } + InterpreterError::TypeUnsupported { typ, location } => { + let msg = + format!("The type `{typ}` is currently unsupported in comptime expressions"); + CustomDiagnostic::simple_error(msg, String::new(), location.span) + } + InterpreterError::InvalidValueForUnary { value, operator, location } => { + let msg = format!("`{}` cannot be used with unary {operator}", value.get_type()); + CustomDiagnostic::simple_error(msg, String::new(), location.span) + } + InterpreterError::InvalidValuesForBinary { lhs, rhs, operator, location } => { + let lhs = lhs.get_type(); + let rhs = rhs.get_type(); + let msg = format!("No implementation for `{lhs}` {operator} `{rhs}`",); + CustomDiagnostic::simple_error(msg, String::new(), location.span) + } + InterpreterError::CastToNonNumericType { typ, location } => { + let msg = format!("Cannot cast to non-numeric type `{typ}`"); + CustomDiagnostic::simple_error(msg, String::new(), location.span) + } + InterpreterError::QuoteInRuntimeCode { location } => { + let msg = "`quote` may only be used in comptime code".into(); + CustomDiagnostic::simple_error(msg, String::new(), location.span) + } + InterpreterError::NonStructInConstructor { typ, location } => { + let msg = format!("`{typ}` is not a struct type"); + CustomDiagnostic::simple_error(msg, String::new(), location.span) + } + InterpreterError::CannotInlineMacro { value, location } => { + let msg = "Cannot inline value into runtime code if it contains references".into(); + let secondary = format!("Cannot inline value {value:?}"); + CustomDiagnostic::simple_error(msg, secondary, location.span) + } + InterpreterError::UnquoteFoundDuringEvaluation { location } => { + let msg = "Unquote found during comptime evaluation".into(); + let secondary = "This is a bug".into(); + CustomDiagnostic::simple_error(msg, secondary, location.span) + } + InterpreterError::Unimplemented { item, location } => { + let msg = format!("{item} is currently unimplemented"); + CustomDiagnostic::simple_error(msg, String::new(), location.span) + } + InterpreterError::BreakNotInLoop { location } => { + let msg = "There is no loop to break out of!".into(); + CustomDiagnostic::simple_error(msg, String::new(), location.span) + } + InterpreterError::ContinueNotInLoop { location } => { + let msg = "There is no loop to continue!".into(); + CustomDiagnostic::simple_error(msg, String::new(), location.span) + } + InterpreterError::Break => unreachable!("Uncaught InterpreterError::Break"), + InterpreterError::Continue => unreachable!("Uncaught InterpreterError::Continue"), + } + } +} 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 c01c985a40c..4bdd4eaec9a 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 @@ -506,11 +506,8 @@ impl<'a> Interpreter<'a> { Value::U64(value) => Ok(Value::U64(0 - value)), value => { let location = self.interner.expr_location(&id); - Err(InterpreterError::InvalidValueForUnary { - value, - location, - operator: "minus", - }) + let operator = "minus"; + Err(InterpreterError::InvalidValueForUnary { value, location, operator }) } }, crate::ast::UnaryOp::Not => match rhs { @@ -880,7 +877,7 @@ impl<'a> Interpreter<'a> { if let Some(method) = method { self.call_function(method, arguments, location) } else { - Err(InterpreterError::NoMethodFound { object, typ, location }) + Err(InterpreterError::NoMethodFound { name: method_name.clone(), typ, location }) } } 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 26e05d675b3..148fa56b4cb 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 @@ -5,4 +5,5 @@ mod scan; mod tests; mod value; +pub use errors::InterpreterError; pub use interpreter::Interpreter; 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 7805f36cdb2..d8839b33ff4 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,7 +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::comptime::{Interpreter, InterpreterError}; use crate::hir::def_map::{CrateDefMap, LocalModuleId, ModuleId}; use crate::hir::resolution::errors::ResolverError; @@ -155,6 +155,7 @@ pub enum CompilationError { DefinitionError(DefCollectorErrorKind), ResolverError(ResolverError), TypeError(TypeCheckError), + InterpreterError(InterpreterError), } impl From for CustomDiagnostic { @@ -164,6 +165,7 @@ impl From for CustomDiagnostic { CompilationError::DefinitionError(error) => error.into(), CompilationError::ResolverError(error) => error.into(), CompilationError::TypeError(error) => error.into(), + CompilationError::InterpreterError(error) => error.into(), } } } @@ -500,13 +502,15 @@ impl ResolvedModule { } /// Evaluate all `comptime` expressions in this module - fn evaluate_comptime(&self, interner: &mut NodeInterner) { + fn evaluate_comptime(&mut 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(); + // The file returned by the error may be different than the file the + // function is in so only use the error's file id. + if let Err(error) = interpreter.scan_function(*function) { + self.errors.push(error.into_compilation_error_pair()); + } } } diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/def_map/mod.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/def_map/mod.rs index 7c0090ff95b..590c2e3d6b6 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir/def_map/mod.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/def_map/mod.rs @@ -5,8 +5,8 @@ use crate::macros_api::MacroProcessor; 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_arena::{Arena, Index}; use noirc_errors::Location; use std::collections::{BTreeMap, HashMap}; mod module_def; diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/errors.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/errors.rs index 0fac6f96086..70e7a8e40f2 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/errors.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/errors.rs @@ -86,6 +86,10 @@ pub enum ResolverError { JumpInConstrainedFn { is_break: bool, span: Span }, #[error("break/continue are only allowed within loops")] JumpOutsideLoop { is_break: bool, span: Span }, + #[error("#[inline(tag)] attribute is only allowed on constrained functions")] + InlineAttributeOnUnconstrained { ident: Ident }, + #[error("#[fold] attribute is only allowed on constrained functions")] + FoldAttributeOnUnconstrained { ident: Ident }, } impl ResolverError { @@ -340,6 +344,30 @@ impl From for Diagnostic { span, ) }, + ResolverError::InlineAttributeOnUnconstrained { ident } => { + let name = &ident.0.contents; + + let mut diag = Diagnostic::simple_error( + format!("misplaced #[inline(tag)] attribute on unconstrained function {name}. Only allowed on constrained functions"), + "misplaced #[inline(tag)] attribute".to_string(), + ident.0.span(), + ); + + diag.add_note("The `#[inline(tag)]` attribute specifies to the compiler whether it should diverge from auto-inlining constrained functions".to_owned()); + diag + } + ResolverError::FoldAttributeOnUnconstrained { ident } => { + let name = &ident.0.contents; + + let mut diag = Diagnostic::simple_error( + format!("misplaced #[fold] attribute on unconstrained function {name}. Only allowed on constrained functions"), + "misplaced #[fold] attribute".to_string(), + ident.0.span(), + ); + + diag.add_note("The `#[fold]` attribute specifies whether a constrained function should be treated as a separate circuit rather than inlined into the program entry point".to_owned()); + diag + } } } } 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 2f2677def88..b1f9e536aa5 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 @@ -926,7 +926,23 @@ impl<'a> Resolver<'a> { let name_ident = HirIdent::non_trait_method(id, location); let attributes = func.attributes().clone(); + let has_inline_attribute = attributes.is_inline(); let should_fold = attributes.is_foldable(); + if !self.inline_attribute_allowed(func) { + if has_inline_attribute { + self.push_err(ResolverError::InlineAttributeOnUnconstrained { + ident: func.name_ident().clone(), + }); + } else if should_fold { + self.push_err(ResolverError::FoldAttributeOnUnconstrained { + ident: func.name_ident().clone(), + }); + } + } + // Both the #[fold] and #[inline(tag)] alter a function's inline type and code generation in similar ways. + // In certain cases such as type checking (for which the following flag will be used) both attributes + // indicate we should code generate in the same way. Thus, we unify the attributes into one flag here. + let has_inline_or_fold_attribute = has_inline_attribute || should_fold; let mut generics = vecmap(&self.generics, |(_, typevar, _)| typevar.clone()); let mut parameters = vec![]; @@ -1021,7 +1037,7 @@ impl<'a> Resolver<'a> { has_body: !func.def.body.is_empty(), trait_constraints: self.resolve_trait_constraints(&func.def.where_clause), is_entry_point: self.is_entry_point_function(func), - should_fold, + has_inline_or_fold_attribute, } } @@ -1057,6 +1073,12 @@ impl<'a> Resolver<'a> { } } + fn inline_attribute_allowed(&self, func: &NoirFunction) -> bool { + // Inline attributes are only relevant for constrained functions + // as all unconstrained functions are not inlined + !func.def.is_unconstrained + } + fn declare_numeric_generics(&mut self, params: &[Type], return_type: &Type) { if self.generics.is_empty() { return; diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/type_check/mod.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/type_check/mod.rs index 44dab6dee3d..03ebb44fa1f 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir/type_check/mod.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/type_check/mod.rs @@ -173,7 +173,7 @@ fn check_if_type_is_valid_for_program_input( ) { let meta = type_checker.interner.function_meta(&func_id); if (meta.is_entry_point && !param.1.is_valid_for_program_input()) - || (meta.should_fold && !param.1.is_valid_non_inlined_function_input()) + || (meta.has_inline_or_fold_attribute && !param.1.is_valid_non_inlined_function_input()) { let span = param.0.span(); errors.push(TypeCheckError::InvalidTypeForEntryPoint { span }); @@ -545,7 +545,7 @@ pub mod test { trait_constraints: Vec::new(), direct_generics: Vec::new(), is_entry_point: true, - should_fold: false, + has_inline_or_fold_attribute: false, }; interner.push_fn_meta(func_meta, func_id); @@ -672,7 +672,7 @@ pub mod test { } fn local_module_id(&self) -> LocalModuleId { - LocalModuleId(arena::Index::unsafe_zeroed()) + LocalModuleId(noirc_arena::Index::unsafe_zeroed()) } fn module_id(&self) -> ModuleId { @@ -724,7 +724,7 @@ pub mod test { let mut def_maps = BTreeMap::new(); let file = FileId::default(); - let mut modules = arena::Arena::default(); + let mut modules = noirc_arena::Arena::default(); let location = Location::new(Default::default(), file); modules.insert(ModuleData::new(None, location, false)); diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir_def/function.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir_def/function.rs index 67b6412a21c..57d3038a135 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir_def/function.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir_def/function.rs @@ -126,8 +126,8 @@ pub struct FuncMeta { pub is_entry_point: bool, /// True if this function is marked with an attribute - /// that indicates it should not be inlined, such as for folding. - pub should_fold: bool, + /// that indicates it should not be inlined, such as `fold` or `inline(never)` + pub has_inline_or_fold_attribute: bool, } impl FuncMeta { 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 0242fc7e7ff..82e17ac3912 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/lexer/token.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/lexer/token.rs @@ -581,6 +581,10 @@ impl Attributes { pub fn is_foldable(&self) -> bool { self.function.as_ref().map_or(false, |func_attribute| func_attribute.is_foldable()) } + + pub fn is_inline(&self) -> bool { + self.function.as_ref().map_or(false, |func_attribute| func_attribute.is_inline()) + } } /// An Attribute can be either a Primary Attribute or a Secondary Attribute @@ -641,6 +645,10 @@ impl Attribute { ["test"] => Attribute::Function(FunctionAttribute::Test(TestScope::None)), ["recursive"] => Attribute::Function(FunctionAttribute::Recursive), ["fold"] => Attribute::Function(FunctionAttribute::Fold), + ["inline", tag] => { + validate(tag)?; + Attribute::Function(FunctionAttribute::Inline(tag.to_string())) + } ["test", name] => { validate(name)?; let malformed_scope = @@ -693,6 +701,7 @@ pub enum FunctionAttribute { Test(TestScope), Recursive, Fold, + Inline(String), } impl FunctionAttribute { @@ -725,6 +734,13 @@ impl FunctionAttribute { pub fn is_foldable(&self) -> bool { matches!(self, FunctionAttribute::Fold) } + + /// Check whether we have an `inline` attribute + /// Although we also do not want to inline foldable functions, + /// we keep the two attributes distinct for clarity. + pub fn is_inline(&self) -> bool { + matches!(self, FunctionAttribute::Inline(_)) + } } impl fmt::Display for FunctionAttribute { @@ -736,6 +752,7 @@ impl fmt::Display for FunctionAttribute { FunctionAttribute::Oracle(ref k) => write!(f, "#[oracle({k})]"), FunctionAttribute::Recursive => write!(f, "#[recursive]"), FunctionAttribute::Fold => write!(f, "#[fold]"), + FunctionAttribute::Inline(ref k) => write!(f, "#[inline({k})]"), } } } @@ -781,6 +798,7 @@ impl AsRef for FunctionAttribute { FunctionAttribute::Test { .. } => "", FunctionAttribute::Recursive => "", FunctionAttribute::Fold => "", + FunctionAttribute::Inline(string) => string, } } } diff --git a/noir/noir-repo/compiler/noirc_frontend/src/monomorphization/ast.rs b/noir/noir-repo/compiler/noirc_frontend/src/monomorphization/ast.rs index ef3af57d303..468938ecf08 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/monomorphization/ast.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/monomorphization/ast.rs @@ -5,8 +5,11 @@ use noirc_errors::{ Location, }; -use crate::ast::{BinaryOpKind, Distinctness, IntegerBitSize, Signedness, Visibility}; use crate::hir_def::{function::FunctionSignature, types::Type as HirType}; +use crate::{ + ast::{BinaryOpKind, Distinctness, IntegerBitSize, Signedness, Visibility}, + token::{Attributes, FunctionAttribute}, +}; /// The monomorphized AST is expression-based, all statements are also /// folded into this expression enum. Compared to the HIR, the monomorphized @@ -200,6 +203,60 @@ pub enum LValue { pub type Parameters = Vec<(LocalId, /*mutable:*/ bool, /*name:*/ String, Type)>; +/// Represents how an Acir function should be inlined. +/// This type is only relevant for ACIR functions as we do not inline any Brillig functions +#[derive(Default, Clone, Copy, PartialEq, Eq, Debug, Hash)] +pub enum InlineType { + /// The most basic entry point can expect all its functions to be inlined. + /// All function calls are expected to be inlined into a single ACIR. + #[default] + Inline, + /// Functions marked as foldable will not be inlined and compiled separately into ACIR + Fold, + /// Similar to `Fold`, these functions will not be inlined and compile separately into ACIR. + /// They are different from `Fold` though as they are expected to be inlined into the program + /// entry point before being used in the backend. + Never, +} + +impl From<&Attributes> for InlineType { + fn from(attributes: &Attributes) -> Self { + attributes.function.as_ref().map_or(InlineType::default(), |func_attribute| { + match func_attribute { + FunctionAttribute::Fold => InlineType::Fold, + FunctionAttribute::Inline(tag) => { + if tag == "never" { + InlineType::Never + } else { + InlineType::default() + } + } + _ => InlineType::default(), + } + }) + } +} + +impl InlineType { + pub fn is_entry_point(&self) -> bool { + match self { + InlineType::Inline => false, + InlineType::Fold => true, + InlineType::Never => true, + } + } +} + +impl std::fmt::Display for InlineType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + InlineType::Inline => write!(f, "inline"), + InlineType::Fold => write!(f, "fold"), + InlineType::Never => write!(f, "inline(never)"), + } + } +} + #[derive(Debug, Clone, Hash)] pub struct Function { pub id: FuncId, @@ -210,7 +267,7 @@ pub struct Function { pub return_type: Type, pub unconstrained: bool, - pub should_fold: bool, + pub inline_type: InlineType, pub func_sig: FunctionSignature, } 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 d7213667c48..c831e4be245 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/monomorphization/mod.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/monomorphization/mod.rs @@ -30,6 +30,7 @@ use std::{ unreachable, }; +use self::ast::InlineType; use self::debug_types::DebugTypeTracker; use self::{ ast::{Definition, FuncId, Function, LocalId, Program}, @@ -132,7 +133,7 @@ pub fn monomorphize_debug( .finished_functions .iter() .flat_map(|(_, f)| { - if f.should_fold || f.id == Program::main_id() { + if f.inline_type.is_entry_point() || f.id == Program::main_id() { Some(f.func_sig.clone()) } else { None @@ -304,7 +305,8 @@ impl<'interner> Monomorphizer<'interner> { let return_type = Self::convert_type(return_type, meta.location)?; let unconstrained = modifiers.is_unconstrained; - let should_fold = meta.should_fold; + let attributes = self.interner.function_attributes(&f); + let inline_type = InlineType::from(attributes); let parameters = self.parameters(&meta.parameters)?; let body = self.expr(body_expr_id)?; @@ -315,7 +317,7 @@ impl<'interner> Monomorphizer<'interner> { body, return_type, unconstrained, - should_fold, + inline_type, func_sig, }; @@ -1399,7 +1401,7 @@ impl<'interner> Monomorphizer<'interner> { body, return_type, unconstrained, - should_fold: false, + inline_type: InlineType::default(), func_sig: FunctionSignature::default(), }; self.push_function(id, function); @@ -1525,7 +1527,7 @@ impl<'interner> Monomorphizer<'interner> { body, return_type, unconstrained, - should_fold: false, + inline_type: InlineType::default(), func_sig: FunctionSignature::default(), }; self.push_function(id, function); @@ -1650,7 +1652,7 @@ impl<'interner> Monomorphizer<'interner> { body, return_type, unconstrained, - should_fold: false, + inline_type: InlineType::default(), func_sig: FunctionSignature::default(), }; self.push_function(id, function); 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 9d3a79820dc..5e4fa3df6c5 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/node_interner.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/node_interner.rs @@ -2,9 +2,9 @@ use std::borrow::Cow; use std::collections::HashMap; use std::ops::Deref; -use arena::{Arena, Index}; use fm::FileId; use iter_extended::vecmap; +use noirc_arena::{Arena, Index}; use noirc_errors::{Location, Span, Spanned}; use petgraph::algo::tarjan_scc; use petgraph::prelude::DiGraph; diff --git a/noir/noir-repo/compiler/noirc_frontend/src/resolve_locations.rs b/noir/noir-repo/compiler/noirc_frontend/src/resolve_locations.rs index b5f1b1d0c64..ac8c96a092e 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/resolve_locations.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/resolve_locations.rs @@ -1,4 +1,4 @@ -use arena::Index; +use noirc_arena::Index; use noirc_errors::Location; use crate::hir_def::expr::HirExpression; diff --git a/noir/noir-repo/compiler/noirc_frontend/src/tests.rs b/noir/noir-repo/compiler/noirc_frontend/src/tests.rs index 31bf2245b1f..5d0f2472a43 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/tests.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/tests.rs @@ -31,8 +31,8 @@ mod test { hir::def_map::{CrateDefMap, LocalModuleId}, parse_program, }; - use arena::Arena; use fm::FileManager; + use noirc_arena::Arena; pub(crate) fn has_parser_error(errors: &[(CompilationError, FileId)]) -> bool { errors.iter().any(|(e, _f)| matches!(e, CompilationError::ParseError(_))) @@ -1282,4 +1282,36 @@ fn lambda$f1(mut env$l1: (Field)) -> Field { "#; assert_eq!(get_program_errors(src).len(), 0); } + + #[test] + fn deny_inline_attribute_on_unconstrained() { + let src = r#" + #[inline(never)] + unconstrained fn foo(x: Field, y: Field) { + assert(x != y); + } + "#; + let errors = get_program_errors(src); + assert_eq!(errors.len(), 1); + assert!(matches!( + errors[0].0, + CompilationError::ResolverError(ResolverError::InlineAttributeOnUnconstrained { .. }) + )); + } + + #[test] + fn deny_fold_attribute_on_unconstrained() { + let src = r#" + #[fold] + unconstrained fn foo(x: Field, y: Field) { + assert(x != y); + } + "#; + let errors = get_program_errors(src); + assert_eq!(errors.len(), 1); + assert!(matches!( + errors[0].0, + CompilationError::ResolverError(ResolverError::FoldAttributeOnUnconstrained { .. }) + )); + } } diff --git a/noir/noir-repo/docs/docs/noir/standard_library/cryptographic_primitives/hashes.mdx b/noir/noir-repo/docs/docs/noir/standard_library/cryptographic_primitives/hashes.mdx index 7329880c7a7..efa52b2c3f2 100644 --- a/noir/noir-repo/docs/docs/noir/standard_library/cryptographic_primitives/hashes.mdx +++ b/noir/noir-repo/docs/docs/noir/standard_library/cryptographic_primitives/hashes.mdx @@ -13,18 +13,21 @@ import BlackBoxInfo from '@site/src/components/Notes/_blackbox.mdx'; ## sha256 Given an array of bytes, returns the resulting sha256 hash. +Specify a message_size to hash only the first `message_size` bytes of the input. #include_code sha256 noir_stdlib/src/hash.nr rust example: +#include_code sha256_var test_programs/execution_success/sha256/src/main.nr rust ```rust fn main() { let x = [163, 117, 178, 149]; // some random bytes - let hash = std::hash::sha256(x); + let hash = std::sha256::sha256_var(x, 4); } ``` + ## blake2s diff --git a/noir/noir-repo/flake.lock b/noir/noir-repo/flake.lock deleted file mode 100644 index 5a9f9470a1f..00000000000 --- a/noir/noir-repo/flake.lock +++ /dev/null @@ -1,170 +0,0 @@ -{ - "nodes": { - "crane": { - "inputs": { - "flake-compat": [ - "flake-compat" - ], - "flake-utils": [ - "flake-utils" - ], - "nixpkgs": [ - "nixpkgs" - ], - "rust-overlay": "rust-overlay" - }, - "locked": { - "lastModified": 1681177078, - "narHash": "sha256-ZNIjBDou2GOabcpctiQykEQVkI8BDwk7TyvlWlI4myE=", - "owner": "ipetkov", - "repo": "crane", - "rev": "0c9f468ff00576577d83f5019a66c557ede5acf6", - "type": "github" - }, - "original": { - "owner": "ipetkov", - "repo": "crane", - "type": "github" - } - }, - "fenix": { - "inputs": { - "nixpkgs": [ - "nixpkgs" - ], - "rust-analyzer-src": "rust-analyzer-src" - }, - "locked": { - "lastModified": 1694499657, - "narHash": "sha256-u/fZtLtN7VcDrMMVrdsFy93PEkaiK+tNpJT9on4SGdU=", - "owner": "nix-community", - "repo": "fenix", - "rev": "2895ff377cbb3cb6f5dd92066734b0447cb04e20", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "fenix", - "type": "github" - } - }, - "flake-compat": { - "flake": false, - "locked": { - "lastModified": 1673956053, - "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", - "owner": "edolstra", - "repo": "flake-compat", - "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", - "type": "github" - }, - "original": { - "owner": "edolstra", - "repo": "flake-compat", - "type": "github" - } - }, - "flake-utils": { - "inputs": { - "systems": "systems" - }, - "locked": { - "lastModified": 1681202837, - "narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "cfacdce06f30d2b68473a46042957675eebb3401", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, - "nixpkgs": { - "locked": { - "lastModified": 1695559356, - "narHash": "sha256-kXZ1pUoImD9OEbPCwpTz4tHsNTr4CIyIfXb3ocuR8sI=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "261abe8a44a7e8392598d038d2e01f7b33cf26d0", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-23.05", - "repo": "nixpkgs", - "type": "github" - } - }, - "root": { - "inputs": { - "crane": "crane", - "fenix": "fenix", - "flake-compat": "flake-compat", - "flake-utils": "flake-utils", - "nixpkgs": "nixpkgs" - } - }, - "rust-analyzer-src": { - "flake": false, - "locked": { - "lastModified": 1694421477, - "narHash": "sha256-df6YZzR57VFzkOPwIohJfC0fRwgq6yUPbMJkKAtQyAE=", - "owner": "rust-lang", - "repo": "rust-analyzer", - "rev": "cc6c8209cbaf7df55013977cf5cc8488d6b7ff1c", - "type": "github" - }, - "original": { - "owner": "rust-lang", - "ref": "nightly", - "repo": "rust-analyzer", - "type": "github" - } - }, - "rust-overlay": { - "inputs": { - "flake-utils": [ - "crane", - "flake-utils" - ], - "nixpkgs": [ - "crane", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1694484610, - "narHash": "sha256-aeSDkp7fkAqtVjW3QUn7vq7BKNlFul/BiGgdv7rK+mA=", - "owner": "oxalica", - "repo": "rust-overlay", - "rev": "c5b977a7e6a295697fa1f9c42174fd6313b38df4", - "type": "github" - }, - "original": { - "owner": "oxalica", - "repo": "rust-overlay", - "type": "github" - } - }, - "systems": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } - } - }, - "root": "root", - "version": 7 -} diff --git a/noir/noir-repo/noir_stdlib/src/hash.nr b/noir/noir-repo/noir_stdlib/src/hash.nr index 26a9fa6c2c0..ef1cb0889d7 100644 --- a/noir/noir-repo/noir_stdlib/src/hash.nr +++ b/noir/noir-repo/noir_stdlib/src/hash.nr @@ -4,6 +4,7 @@ mod poseidon2; use crate::default::Default; use crate::uint128::U128; +use crate::sha256::{digest, sha256_var}; #[foreign(sha256)] // docs:start:sha256 diff --git a/noir/noir-repo/noir_stdlib/src/sha256.nr b/noir/noir-repo/noir_stdlib/src/sha256.nr index 8ca6808568d..d856043fcfa 100644 --- a/noir/noir-repo/noir_stdlib/src/sha256.nr +++ b/noir/noir-repo/noir_stdlib/src/sha256.nr @@ -17,19 +17,42 @@ fn msg_u8_to_u32(msg: [u8; 64]) -> [u32; 16] { } // SHA-256 hash function pub fn digest(msg: [u8; N]) -> [u8; 32] { + sha256_var(msg, N) +} + +fn hash_final_block(msg_block: [u8; 64], mut state: [u32; 8]) -> [u8; 32] { + let mut out_h: [u8; 32] = [0; 32]; // Digest as sequence of bytes + + // Hash final padded block + state = crate::hash::sha256_compression(msg_u8_to_u32(msg_block), state); + + // Return final hash as byte array + for j in 0..8 { + let h_bytes = (state[7 - j] as Field).to_le_bytes(4); + for k in 0..4 { + out_h[31 - 4*j - k] = h_bytes[k]; + } + } + + out_h +} + +// Variable size SHA-256 hash +pub fn sha256_var(msg: [u8; N], message_size: u64) -> [u8; 32] { let mut msg_block: [u8; 64] = [0; 64]; let mut h: [u32; 8] = [1779033703, 3144134277, 1013904242, 2773480762, 1359893119, 2600822924, 528734635, 1541459225]; // Intermediate hash, starting with the canonical initial value - let mut out_h: [u8; 32] = [0; 32]; // Digest as sequence of bytes let mut i: u64 = 0; // Message byte pointer for k in 0..N { - // Populate msg_block - msg_block[i] = msg[k]; - i = i + 1; - if i == 64 { - // Enough to hash block - h = crate::hash::sha256_compression(msg_u8_to_u32(msg_block), h); + if k < message_size { + // Populate msg_block + msg_block[i] = msg[k]; + i = i + 1; + if i == 64 { + // Enough to hash block + h = crate::hash::sha256_compression(msg_u8_to_u32(msg_block), h); - i = 0; + i = 0; + } } } // Pad the rest such that we have a [u32; 2] block at the end representing the length @@ -53,7 +76,7 @@ pub fn digest(msg: [u8; N]) -> [u8; 32] { i = 0; } - let len = 8 * msg.len(); + let len = 8 * message_size; let len_bytes = (len as Field).to_le_bytes(8); for _i in 0..64 { // In any case, fill blocks up with zeros until the last 64 (i.e. until i = 56). @@ -67,16 +90,5 @@ pub fn digest(msg: [u8; N]) -> [u8; 32] { i += 8; } } - // Hash final padded block - h = crate::hash::sha256_compression(msg_u8_to_u32(msg_block), h); - - // Return final hash as byte array - for j in 0..8 { - let h_bytes = (h[7 - j] as Field).to_le_bytes(4); - for k in 0..4 { - out_h[31 - 4*j - k] = h_bytes[k]; - } - } - - out_h + hash_final_block(msg_block, h) } diff --git a/noir/noir-repo/test_programs/execution_success/inline_never_basic/Nargo.toml b/noir/noir-repo/test_programs/execution_success/inline_never_basic/Nargo.toml new file mode 100644 index 00000000000..16691770d76 --- /dev/null +++ b/noir/noir-repo/test_programs/execution_success/inline_never_basic/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "inline_never_basic" +type = "bin" +authors = [""] +compiler_version = ">=0.27.0" + +[dependencies] \ No newline at end of file diff --git a/noir/noir-repo/test_programs/execution_success/inline_never_basic/Prover.toml b/noir/noir-repo/test_programs/execution_success/inline_never_basic/Prover.toml new file mode 100644 index 00000000000..f28f2f8cc48 --- /dev/null +++ b/noir/noir-repo/test_programs/execution_success/inline_never_basic/Prover.toml @@ -0,0 +1,2 @@ +x = "5" +y = "10" diff --git a/noir/noir-repo/test_programs/execution_success/inline_never_basic/src/main.nr b/noir/noir-repo/test_programs/execution_success/inline_never_basic/src/main.nr new file mode 100644 index 00000000000..1922aaedb6c --- /dev/null +++ b/noir/noir-repo/test_programs/execution_success/inline_never_basic/src/main.nr @@ -0,0 +1,8 @@ +fn main(x: Field, y: pub Field) { + basic_check(x, y); +} + +#[inline(never)] +fn basic_check(x: Field, y: Field) { + assert(x != y); +} diff --git a/noir/noir-repo/test_programs/execution_success/sha256/src/main.nr b/noir/noir-repo/test_programs/execution_success/sha256/src/main.nr index fd5340e2384..d4240ded8b3 100644 --- a/noir/noir-repo/test_programs/execution_success/sha256/src/main.nr +++ b/noir/noir-repo/test_programs/execution_success/sha256/src/main.nr @@ -14,6 +14,8 @@ use dep::std; fn main(x: Field, result: [u8; 32]) { // We use the `as` keyword here to denote the fact that we want to take just the first byte from the x Field // The padding is taken care of by the program - let digest = std::hash::sha256([x as u8]); + // docs:start:sha256_var + let digest = std::hash::sha256_var([x as u8], 1); + // docs:end:sha256_var assert(digest == result); } diff --git a/noir/noir-repo/tooling/debugger/ignored-tests.txt b/noir/noir-repo/tooling/debugger/ignored-tests.txt index 3b63f8d5542..8f49fe273e1 100644 --- a/noir/noir-repo/tooling/debugger/ignored-tests.txt +++ b/noir/noir-repo/tooling/debugger/ignored-tests.txt @@ -17,4 +17,4 @@ fold_basic_nested_call fold_call_witness_condition fold_after_inlined_calls fold_numeric_generic_poseidon - +inline_never_basic diff --git a/noir/noir-repo/tooling/noir_js_backend_barretenberg/package.json b/noir/noir-repo/tooling/noir_js_backend_barretenberg/package.json index 438e91ff302..b5782269674 100644 --- a/noir/noir-repo/tooling/noir_js_backend_barretenberg/package.json +++ b/noir/noir-repo/tooling/noir_js_backend_barretenberg/package.json @@ -3,7 +3,7 @@ "contributors": [ "The Noir Team " ], - "version": "0.27.0", + "version": "0.28.0", "packageManager": "yarn@3.5.1", "license": "(MIT OR Apache-2.0)", "type": "module", diff --git a/noir/noir-repo/tooling/noirc_abi_wasm/build.sh b/noir/noir-repo/tooling/noirc_abi_wasm/build.sh index ee93413ab85..c07d2d8a4c1 100755 --- a/noir/noir-repo/tooling/noirc_abi_wasm/build.sh +++ b/noir/noir-repo/tooling/noirc_abi_wasm/build.sh @@ -25,7 +25,7 @@ function run_if_available { require_command jq require_command cargo require_command wasm-bindgen -# require_command wasm-opt +#require_command wasm-opt self_path=$(dirname "$(readlink -f "$0")") pname=$(cargo read-manifest | jq -r '.name') diff --git a/noir/noir-repo/compiler/utils/iter-extended/Cargo.toml b/noir/noir-repo/utils/iter-extended/Cargo.toml similarity index 100% rename from noir/noir-repo/compiler/utils/iter-extended/Cargo.toml rename to noir/noir-repo/utils/iter-extended/Cargo.toml diff --git a/noir/noir-repo/compiler/utils/iter-extended/src/lib.rs b/noir/noir-repo/utils/iter-extended/src/lib.rs similarity index 100% rename from noir/noir-repo/compiler/utils/iter-extended/src/lib.rs rename to noir/noir-repo/utils/iter-extended/src/lib.rs