Skip to content

Commit

Permalink
Merge branch 'master' into phated/nargo-crate-type
Browse files Browse the repository at this point in the history
* master:
  chore: replace usage of `Directive::Quotient` with brillig opcode  (#1766)
  chore: clippy fix (#2136)
  feat: Initial work on rewriting closures to regular functions with hi… (#1959)
  chore: Decouple acir blockid from ssa valueid (#2103)
  chore: Initialize copy array from previous values in `array_set` (#2106)
  chore: rename `ssa_refactor` module to `ssa` (#2129)
  chore: Use `--show-output` flag on execution rather than compilation  (#2116)
  fix(globals): Accurately filter literals for resolving globals (#2126)
  feat: Optimize away constant calls to black box functions (#1981)
  • Loading branch information
TomAFrench committed Aug 3, 2023
2 parents b39fd45 + 8e976ea commit 97a3087
Show file tree
Hide file tree
Showing 77 changed files with 1,668 additions and 462 deletions.
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,3 @@ result
**/target
!crates/nargo_cli/tests/test_data/*/target
!crates/nargo_cli/tests/test_data/*/target/witness.tr
!crates/nargo_cli/tests/test_data_ssa_refactor/*/target
!crates/nargo_cli/tests/test_data_ssa_refactor/*/target/witness.tr
3 changes: 2 additions & 1 deletion crates/nargo/src/ops/execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub fn execute_circuit<B: BlackBoxFunctionSolver + Default>(
_backend: &B,
circuit: Circuit,
initial_witness: WitnessMap,
show_output: bool,
) -> Result<WitnessMap, NargoError> {
let mut acvm = ACVM::new(B::default(), circuit.opcodes, initial_witness);

Expand All @@ -23,7 +24,7 @@ pub fn execute_circuit<B: BlackBoxFunctionSolver + Default>(
}
ACVMStatus::Failure(error) => return Err(error.into()),
ACVMStatus::RequiresForeignCall(foreign_call) => {
let foreign_call_result = ForeignCall::execute(&foreign_call)?;
let foreign_call_result = ForeignCall::execute(&foreign_call, show_output)?;
acvm.resolve_pending_foreign_call(foreign_call_result);
}
}
Expand Down
5 changes: 4 additions & 1 deletion crates/nargo/src/ops/foreign_calls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,14 @@ impl ForeignCall {

pub(crate) fn execute(
foreign_call: &ForeignCallWaitInfo,
show_output: bool,
) -> Result<ForeignCallResult, ForeignCallError> {
let foreign_call_name = foreign_call.function.as_str();
match Self::lookup(foreign_call_name) {
Some(ForeignCall::Println) => {
Self::execute_println(&foreign_call.inputs)?;
if show_output {
Self::execute_println(&foreign_call.inputs)?;
}
Ok(ForeignCallResult { values: vec![] })
}
Some(ForeignCall::Sequence) => {
Expand Down
2 changes: 1 addition & 1 deletion crates/nargo_cli/src/cli/execute_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ pub(crate) fn execute_program<B: Backend>(
debug_data: Option<(DebugInfo, Context)>,
) -> Result<WitnessMap, CliError<B>> {
let initial_witness = abi.encode(inputs_map, None)?;
let solved_witness_err = nargo::ops::execute_circuit(backend, circuit, initial_witness);
let solved_witness_err = nargo::ops::execute_circuit(backend, circuit, initial_witness, true);
match solved_witness_err {
Ok(solved_witness) => Ok(solved_witness),
Err(err) => {
Expand Down
9 changes: 6 additions & 3 deletions crates/nargo_cli/src/cli/test_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,14 +106,17 @@ fn run_test<B: Backend>(
show_output: bool,
config: &CompileOptions,
) -> Result<(), CliError<B>> {
let mut program = compile_no_check(context, show_output, config, main)
.map_err(|_| CliError::Generic(format!("Test '{test_name}' failed to compile")))?;
let mut program = compile_no_check(context, config, main).map_err(|err| {
noirc_errors::reporter::report_all(&context.file_manager, &[err], config.deny_warnings);
CliError::Generic(format!("Test '{test_name}' failed to compile"))
})?;

// Note: We could perform this test using the unoptimized ACIR as generated by `compile_no_check`.
program.circuit = optimize_circuit(backend, program.circuit).unwrap().0;

// Run the backend to ensure the PWG evaluates functions like std::hash::pedersen,
// otherwise constraints involving these expressions will not error.
match execute_circuit(backend, program.circuit, WitnessMap::new()) {
match execute_circuit(backend, program.circuit, WitnessMap::new(), show_output) {
Ok(_) => Ok(()),
Err(error) => {
let writer = StandardStream::stderr(ColorChoice::Always);
Expand Down
6 changes: 6 additions & 0 deletions crates/nargo_cli/tests/test_data/closures_mut_ref/Nargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "closures_mut_ref"
authors = [""]
compiler_version = "0.8.0"

[dependencies]
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
x = "0"
20 changes: 20 additions & 0 deletions crates/nargo_cli/tests/test_data/closures_mut_ref/src/main.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use dep::std;

fn main(mut x: Field) {
let one = 1;
let add1 = |z| {
*z = *z + one;
};

let two = 2;
let add2 = |z| {
*z = *z + two;
};

add1(&mut x);
assert(x == 1);

add2(&mut x);
assert(x == 3);

}
7 changes: 7 additions & 0 deletions crates/nargo_cli/tests/test_data/global_consts/src/main.nr
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,19 @@ struct Dummy {
y: [Field; foo::MAGIC_NUMBER]
}

struct Test {
v: Field,
}
global VALS: [Test; 1] = [Test { v: 100 }];
global NESTED = [VALS, VALS];

fn main(a: [Field; M + N - N], b: [Field; 30 + N / 2], c : pub [Field; foo::MAGIC_NUMBER], d: [Field; foo::bar::N]) {
let test_struct = Dummy { x: d, y: c };

for i in 0..foo::MAGIC_NUMBER {
assert(c[i] == foo::MAGIC_NUMBER);
assert(test_struct.y[i] == foo::MAGIC_NUMBER);
assert(test_struct.y[i] != NESTED[1][0].v);
}

assert(N != M);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "higher_order_fn_selector"
authors = [""]
compiler_version = "0.8.0"

[dependencies]
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use dep::std;

fn g(x: &mut Field) -> () {
*x *= 2;
}

fn h(x: &mut Field) -> () {
*x *= 3;
}

fn selector(flag: &mut bool) -> fn(&mut Field) -> () {
let my_func = if *flag {
g
} else {
h
};

// Flip the flag for the next function call
*flag = !(*flag);
my_func
}

fn main() {

let mut flag: bool = true;

let mut x: Field = 100;
let returned_func = selector(&mut flag);
returned_func(&mut x);

assert(x == 200);

let mut y: Field = 100;
let returned_func2 = selector(&mut flag);
returned_func2(&mut y);

assert(y == 300);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "higher_order_functions"
authors = [""]
compiler_version = "0.1"

[dependencies]
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
use dep::std;

fn main() -> pub Field {
let f = if 3 * 7 > 200 as u32 { foo } else { bar };
assert(f()[1] == 2);
// Lambdas:
assert(twice(|x| x * 2, 5) == 20);
assert((|x, y| x + y + 1)(2, 3) == 6);

// nested lambdas
assert((|a, b| {
a + (|c| c + 2)(b)
})(0, 1) == 3);


// Closures:
let a = 42;
let g = || a;
assert(g() == 42);

// When you copy mutable variables,
// the capture of the copies shouldn't change:
let mut x = 2;
x = x + 1;
let z = x;

// Add extra mutations to ensure we can mutate x without the
// captured z changing.
x = x + 1;
assert((|y| y + z)(1) == 4);

// When you capture mutable variables,
// again, the captured variable doesn't change:
let closure_capturing_mutable = (|y| y + x);
assert(closure_capturing_mutable(1) == 5);
x += 1;
assert(closure_capturing_mutable(1) == 5);

let ret = twice(add1, 3);

test_array_functions();
ret
}

/// Test the array functions in std::array
fn test_array_functions() {
let myarray: [i32; 3] = [1, 2, 3];
assert(myarray.any(|n| n > 2));

let evens: [i32; 3] = [2, 4, 6];
assert(evens.all(|n| n > 1));

assert(evens.fold(0, |a, b| a + b) == 12);
assert(evens.reduce(|a, b| a + b) == 12);

// TODO: is this a sort_via issue with the new backend,
// or something more general?
//
// currently it fails only with `--experimental-ssa` with
// "not yet implemented: Cast into signed"
// but it worked with the original ssa backend
// (before dropping it)
//
// opened #2121 for it
// https://github.com/noir-lang/noir/issues/2121

// let descending = myarray.sort_via(|a, b| a > b);
// assert(descending == [3, 2, 1]);

assert(evens.map(|n| n / 2) == myarray);
}

fn foo() -> [u32; 2] {
[1, 3]
}

fn bar() -> [u32; 2] {
[3, 2]
}

fn add1(x: Field) -> Field {
x + 1
}

fn twice(f: fn(Field) -> Field, x: Field) -> Field {
f(f(x))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"backend":"acvm-backend-barretenberg","abi":{"parameters":[],"param_witnesses":{},"return_type":null,"return_witnesses":[]},"bytecode":[155,194,56,97,194,4,0],"proving_key":null,"verification_key":null}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"backend":"acvm-backend-barretenberg","abi":{"parameters":[{"name":"x","type":{"kind":"integer","sign":"unsigned","width":32},"visibility":"private"},{"name":"y","type":{"kind":"integer","sign":"unsigned","width":32},"visibility":"private"},{"name":"z","type":{"kind":"integer","sign":"unsigned","width":32},"visibility":"private"}],"param_witnesses":{"x":[1],"y":[2],"z":[3]},"return_type":null,"return_witnesses":[]},"bytecode":"H4sIAAAAAAAA/9WUTW6DMBSEJ/yFhoY26bYLjoAxBLPrVYpK7n+EgmoHamWXeShYQsYSvJ+Z9/kDwCf+1m58ArsXi3PgnUN7dt/u7P9fdi8fW8rlATduCW89GFe5l2iMES90YBd+EyTyjIjtGYIm+HF1eanroa0GpdV3WXW9acq66S9GGdWY5qcyWg+mNm3Xd23ZqVoP6tp0+moDJ5AxNOTUWdk6VUTsOSb6wtRPCuDYziaZAzGA92OMFCsAPCUqMAOcQg5gZwIb4BdsA+A9seeU6AtTPymAUzubZA7EAD6MMTKsAPCUqMAMcAY5gJ0JbIBfsQ2AD8SeM6IvTP2kAM7sbJI5EAP4OMbIsQLAU6ICM8A55AB2JrABfsM2AD4Se86Jvjy5freeQ2LPObGud6J+Ce5ADz6LzJqX9Z4W75HdgzszkQj0BC+Pr6PohSpl0kkg7hm84Zfq+8z36N/l9OyaLtcv2EfpKJUUAAA=","proving_key":null,"verification_key":null}
Binary file not shown.
6 changes: 6 additions & 0 deletions crates/nargo_cli/tests/test_data/inner_outer_cl/Nargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "inner_outer_cl"
authors = [""]
compiler_version = "0.7.1"

[dependencies]
12 changes: 12 additions & 0 deletions crates/nargo_cli/tests/test_data/inner_outer_cl/src/main.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
fn main() {
let z1 = 0;
let z2 = 1;
let cl_outer = |x| {
let cl_inner = |y| {
x + y + z2
};
cl_inner(1) + z1
};
let result = cl_outer(1);
assert(result == 3);
}
6 changes: 6 additions & 0 deletions crates/nargo_cli/tests/test_data/ret_fn_ret_cl/Nargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "ret_fn_ret_cl"
authors = [""]
compiler_version = "0.7.1"

[dependencies]
1 change: 1 addition & 0 deletions crates/nargo_cli/tests/test_data/ret_fn_ret_cl/Prover.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
x = "10"
39 changes: 39 additions & 0 deletions crates/nargo_cli/tests/test_data/ret_fn_ret_cl/src/main.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use dep::std;

fn f(x: Field) -> Field {
x + 1
}

fn ret_fn() -> fn(Field) -> Field {
f
}

// TODO: in the advanced implicitly generic function with closures branch
// which would support higher-order functions in a better way
// support returning closures:
//
// fn ret_closure() -> fn(Field) -> Field {
// let y = 1;
// let inner_closure = |z| -> Field{
// z + y
// };
// inner_closure
// }

fn ret_lambda() -> fn(Field) -> Field {
let cl = |z: Field| -> Field {
z + 1
};
cl
}

fn main(x : Field) {
let result_fn = ret_fn();
assert(result_fn(x) == x + 1);

// let result_closure = ret_closure();
// assert(result_closure(x) == x + 1);

let result_lambda = ret_lambda();
assert(result_lambda(x) == x + 1);
}
26 changes: 22 additions & 4 deletions crates/nargo_cli/tests/test_data/strings/src/main.nr
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
use dep::std;

// Test global string literals
global HELLO_WORLD = "hello world";

fn main(message : pub str<11>, y : Field, hex_as_string : str<4>, hex_as_field : Field) {
let mut bad_message = "hello world";

assert(message == "hello world");
bad_message = "helld world";
assert(message == HELLO_WORLD);
let x = 10;
let z = x * 5;
std::println(10);
Expand All @@ -16,6 +19,7 @@ fn main(message : pub str<11>, y : Field, hex_as_string : str<4>, hex_as_field :
assert(y == 5); // Change to y != 5 to see how the later print statements are not called
std::println(array);

bad_message = "helld world";
std::println(bad_message);
assert(message != bad_message);

Expand All @@ -39,16 +43,30 @@ fn test_prints_strings() {
fn test_prints_array() {
let array = [1, 2, 3, 5, 8];

// TODO: Printing structs currently not supported
// let s = Test { a: 1, b: 2, c: [3, 4] };
// std::println(s);
let s = Test { a: 1, b: 2, c: [3, 4] };
std::println(s);

std::println(array);

let hash = std::hash::pedersen(array);
std::println(hash);
}

fn failed_constraint(hex_as_field: Field) {
// TODO(#2116): Note that `println` will not work if a failed constraint can be
// evaluated at compile time.
// When this method is called from a test method or with constant values
// a `Failed constraint` compile error will be caught before this `println`
// is executed as the input will be a constant.
std::println(hex_as_field);
assert(hex_as_field != 0x41);
}

#[test]
fn test_failed_constraint() {
failed_constraint(0x41);
}

struct Test {
a: Field,
b: Field,
Expand Down
Loading

0 comments on commit 97a3087

Please sign in to comment.