diff --git a/compiler/noirc_evaluator/src/ssa/opt/mem2reg.rs b/compiler/noirc_evaluator/src/ssa/opt/mem2reg.rs index 717755ac22e..ed311470544 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/mem2reg.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/mem2reg.rs @@ -1833,4 +1833,128 @@ mod tests { "#; assert_ssa_does_not_change(src, Ssa::mem2reg); } + + #[test] + fn does_not_remove_store_used_in_if_then() { + let src = " + brillig(inline) fn func f0 { + b0(v0: &mut u1, v1: u1): + v2 = allocate -> &mut u1 + store v1 at v2 + jmp b1() + b1(): + v3 = not v1 + v4 = if v1 then v0 else (if v3) v2 + v6 = call f0(v4, v1) -> Field + return v6 + } + "; + assert_ssa_does_not_change(src, Ssa::mem2reg); + } + + #[test] + fn block_argument_is_alias_of_block_parameter_1() { + // Here the last load can't be replaced with `Field 0` as v0 and v1 are aliases of one another. + let src = " + brillig(inline) impure fn main f0 { + b0(): + v0 = allocate -> &mut Field + store Field 0 at v0 + jmp b1(v0) + b1(v1: &mut Field): + store Field 1 at v1 + v2 = load v0 -> Field + return v2 + } + "; + assert_ssa_does_not_change(src, Ssa::mem2reg); + } + + #[test] + fn block_argument_is_alias_of_block_parameter_2() { + // Here the last load can't be replaced with `Field 1` as v0 and v1 are aliases of one another. + let src = " + brillig(inline) impure fn main f0 { + b0(): + v0 = allocate -> &mut Field + store Field 0 at v0 + jmp b1(v0) + b1(v1: &mut Field): + store Field 1 at v1 + store Field 2 at v0 + v2 = load v1 -> Field + return v2 + } + "; + assert_ssa_does_not_change(src, Ssa::mem2reg); + } + + #[test] + fn nested_alias_in_array() { + let src = " + acir(inline) fn regression_2445_deeper_ref f2 { + b0(): + v0 = allocate -> &mut Field + store Field 0 at v0 + v2 = allocate -> &mut &mut Field + store v0 at v2 + v3 = allocate -> &mut &mut &mut Field + store v2 at v3 + v4 = make_array [v3, v3] : [&mut &mut &mut Field; 2] + v5 = allocate -> &mut [&mut &mut &mut Field; 2] + store v4 at v5 + v6 = load v5 -> [&mut &mut &mut Field; 2] + v8 = array_get v6, index u32 0 -> &mut &mut &mut Field + v9 = load v8 -> &mut &mut Field + v10 = load v9 -> &mut Field + store Field 1 at v10 + v12 = load v5 -> [&mut &mut &mut Field; 2] + v14 = array_get v12, index u32 1 -> &mut &mut &mut Field + v15 = load v14 -> &mut &mut Field + v16 = load v15 -> &mut Field + store Field 2 at v16 + v18 = load v0 -> Field + v19 = eq v18, Field 2 + constrain v18 == Field 2 + v20 = load v3 -> &mut &mut Field + v21 = load v20 -> &mut Field + v22 = load v21 -> Field + v23 = eq v22, Field 2 + constrain v22 == Field 2 + v24 = load v5 -> [&mut &mut &mut Field; 2] + v25 = array_get v24, index u32 0 -> &mut &mut &mut Field + v26 = load v25 -> &mut &mut Field + v27 = load v26 -> &mut Field + v28 = load v27 -> Field + v29 = eq v28, Field 2 + constrain v28 == Field 2 + v30 = load v5 -> [&mut &mut &mut Field; 2] + v31 = array_get v30, index u32 1 -> &mut &mut &mut Field + v32 = load v31 -> &mut &mut Field + v33 = load v32 -> &mut Field + v34 = load v33 -> Field + v35 = eq v34, Field 2 + constrain v34 == Field 2 + return + } + "; + let ssa = Ssa::from_str(src).unwrap(); + let ssa = ssa.mem2reg(); + + // We expect the final references to both be resolved to `Field 2` and thus the constrain instructions + // will be trivially true and simplified out. + assert_ssa_snapshot!(ssa, @r" + acir(inline) fn regression_2445_deeper_ref f0 { + b0(): + v0 = allocate -> &mut Field + store Field 0 at v0 + v2 = allocate -> &mut &mut Field + v3 = allocate -> &mut &mut &mut Field + v4 = make_array [v3, v3] : [&mut &mut &mut Field; 2] + v5 = allocate -> &mut [&mut &mut &mut Field; 2] + store Field 1 at v0 + return + } + "); + } } diff --git a/compiler/noirc_evaluator/src/ssa/opt/pure.rs b/compiler/noirc_evaluator/src/ssa/opt/pure.rs index 62ca9dfa124..57bc3ec0e7c 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/pure.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/pure.rs @@ -512,4 +512,113 @@ mod test { assert_eq!(purities[&FunctionId::test_new(0)], Purity::Impure); assert_eq!(purities[&FunctionId::test_new(1)], Purity::Impure); } + + #[test] + fn mutual_recursion_marks_functions_impure() { + // We want to test that two pure mutually recursive functions do in fact mark each other as impure + let src = r#" + acir(inline) fn main f0 { + b0(): + v0 = call f1(u32 4) -> bool + return + } + acir(inline) fn is_even f1 { + b0(v0: u32): + v1 = eq v0, u32 0 + jmpif v1 then: b1, else: b2 + b1(): + jmp b3(u1 1) + b2(): + v2 = unchecked_sub v0, u32 1 + v3 = call f2(v2) -> bool + jmp b3(v3) + b3(v4: bool): + return v4 + } + acir(inline) fn is_odd f2 { + b0(v0: u32): + v1 = eq v0, u32 0 + jmpif v1 then: b1, else: b2 + b1(): + jmp b3(u1 0) + b2(): + v2 = unchecked_sub v0, u32 1 + v3 = call f1(v2) -> bool + jmp b3(v3) + b3(v4: bool): + return v4 + } + "#; + + let ssa = Ssa::from_str(src).unwrap(); + let ssa = ssa.purity_analysis(); + + let purities = &ssa.main().dfg.function_purities; + assert_eq!(purities[&FunctionId::test_new(0)], Purity::Impure); + // Impure due to mutual recursion fallback. + assert_eq!(purities[&FunctionId::test_new(1)], Purity::Impure); + assert_eq!(purities[&FunctionId::test_new(2)], Purity::Impure); + } + + /// TODO(https://github.com/noir-lang/noir/issues/9444) + #[test] + fn brillig_functions_never_pure() { + let src = " + brillig(inline) fn main f0 { + b0(v0: u1): + call f1() + call f1() + return + } + brillig(inline) fn pure_basic f1 { + b0(): + v2 = make_array [Field 0, Field 1] : [Field; 2] + v4 = array_get v2, index u32 1 -> Field + v5 = allocate -> &mut Field + store Field 0 at v5 + return + } + "; + + let ssa = Ssa::from_str(src).unwrap(); + let ssa = ssa.purity_analysis(); + + let purities = &ssa.main().dfg.function_purities; + // PureWithPredicates is the default purity for all Brillig functions. + // So even though `f1` is technically pure it will be marked as PureWithPredicates + assert_eq!(purities[&FunctionId::test_new(0)], Purity::PureWithPredicate); + assert_eq!(purities[&FunctionId::test_new(1)], Purity::PureWithPredicate); + } + + #[test] + fn call_to_function_value() { + let src = r#" + acir(inline) fn main f0 { + b0(v0: u32): + v5 = make_array [f1, f2] : [function; 2] + v7 = lt v0, u32 2 + constrain v7 == u1 1, "Index out of bounds" + v9 = array_get v5, index v0 -> function + call v9() + return + } + acir(inline) fn lambda f1 { + b0(): + return + } + acir(inline) fn lambda f2 { + b0(): + return + }"#; + + let ssa = Ssa::from_str(src).unwrap(); + let ssa = ssa.purity_analysis(); + + let purities = &ssa.main().dfg.function_purities; + // Even though the functions referenced by the function values are pure + // we assume the worse case for functions containing calls to function values. + assert_eq!(purities[&FunctionId::test_new(0)], Purity::Impure); + assert_eq!(purities[&FunctionId::test_new(1)], Purity::Pure); + assert_eq!(purities[&FunctionId::test_new(1)], Purity::Pure); + } } diff --git a/test_programs/compile_success_empty/references_aliasing/src/main.nr b/test_programs/compile_success_empty/references_aliasing/src/main.nr index b2b625477e7..a80d597781e 100644 --- a/test_programs/compile_success_empty/references_aliasing/src/main.nr +++ b/test_programs/compile_success_empty/references_aliasing/src/main.nr @@ -4,14 +4,32 @@ fn main() { increment(xref); assert(*xref == 101); + let mut x_three_refs = &mut &mut &mut x; + increment_deeper_ref(x_three_refs); + assert(***x_three_refs == 102); + regression_2445(); + regression_2445_deeper_ref(); + struct_alias_in_array(); single_alias_inside_loop(); + deeper_ref_in_loop(); + struct_alias_in_loop(); + struct_multi_field_alias(); + struct_multi_field_alias_in_loop(); + struct_multi_field_different_aliases(); + struct_multi_field_different_aliases_in_loop(); + nested_struct_aliases(); + nested_struct_multi_field_different_aliases_in_loop(); + nested_struct_aliases_in_array(); assert(5 == struct_field_refs_across_blocks(MyStruct { a: 5, b: 10 })[0]); } fn increment(mut r: &mut Field) { *r = *r + 1; } +fn increment_deeper_ref(mut r: &mut &mut &mut Field) { + ***r = ***r + 1; +} // If aliasing within arrays and constant folding within the mem2reg pass aren't // handled, we'll fail to optimize out all the references in this function. fn regression_2445() { @@ -29,6 +47,41 @@ fn regression_2445() { assert(**array[1] == 2); } +fn regression_2445_deeper_ref() { + let mut var = 0; + let ref = &mut &mut &mut var; + + let mut array = [ref, ref]; + + ***array[0] = 1; + ***array[1] = 2; + + assert(var == 2); + assert(***ref == 2); + assert(***array[0] == 2); + assert(***array[1] == 2); +} + +struct Foo { + inner: u32, +} + +fn struct_alias_in_array() { + let mut var = Foo { inner: 0 }; + let ref = &mut &mut var; + + let mut array = [ref, ref]; + assert((**array[0]).inner == 0); + + (**array[0]).inner = 1; + (**array[1]).inner = 2; + + assert(var.inner == 2); + assert((**ref).inner == 2); + assert((**array[0]).inner == 2); + assert((**array[1]).inner == 2); +} + fn single_alias_inside_loop() { let mut var = 0; let ref = &mut &mut var; @@ -41,11 +94,171 @@ fn single_alias_inside_loop() { assert(**ref == 2); } +fn deeper_ref_in_loop() { + let mut var = 0; + let ref = &mut &mut &mut var; + + for _ in 0..1 { + ***ref = 2; + } + + assert(var == 2); + assert(***ref == 2); +} + +fn struct_alias_in_loop() { + let mut var = Foo { inner: 0 }; + let ref = &mut &mut var; + + for _ in 0..1 { + (**ref).inner = 1; + (**ref).inner = 2; + } + + assert(var.inner == 2); + assert((**ref).inner == 2); +} + struct MyStruct { a: Field, b: u32, } +fn struct_multi_field_alias() { + let mut var = MyStruct { a: 0, b: 10 }; + let ref = &mut &mut var; + + (**ref).a = 1; + (**ref).b = 20; + + assert(var.a == 1); + assert(var.b == 20); + assert((**ref).a == 1); + assert((**ref).b == 20); +} + +fn struct_multi_field_alias_in_loop() { + let mut var = MyStruct { a: 0, b: 0 }; + let ref = &mut &mut var; + + for _ in 0..1 { + (**ref).a = (**ref).a + 1; + (**ref).b = (**ref).b + 2; + } + + assert(var.a == 1); + assert(var.b == 2); + assert((**ref).a == 1); + assert((**ref).b == 2); +} + +fn struct_multi_field_different_aliases_in_loop() { + let mut var = MyStruct { a: 0, b: 0 }; + let ref_a = &mut var; + let ref_b = &mut var; + + for _ in 0..3 { + (*ref_a).a += 2; + (*ref_b).a += 3; + (*ref_a).b += 1; + (*ref_b).b += 2; + } + + // Updates from the loop: + // a = 0+2+3 = 5, b = 0+1+2 = 3 + // a = 5+2+3 = 10, b = 3+1+2 = 6 + // a = 10+2+3 = 15, b = 6+1+2 = 9 + assert(var.a == 15); + assert(var.b == 9); + + assert((*ref_a).a == 15); + assert((*ref_a).b == 9); + assert((*ref_b).a == 15); + assert((*ref_b).b == 9); +} + +fn struct_multi_field_different_aliases() { + let mut var = MyStruct { a: 0, b: 0 }; + let ref_a = &mut var; + let ref_b = &mut var; + + (*ref_a).a = 10; + (*ref_a).b = 20; + + // Should read the 10 from ref_a and write 15 + (*ref_b).a = (*ref_b).a + 5; + // Should read the 20 from ref_a and write 25 + (*ref_b).b = (*ref_b).b + 5; + + assert(var.a == 15); + assert(var.b == 25); + + assert((*ref_a).a == 15); + assert((*ref_a).b == 25); + assert((*ref_b).a == 15); + assert((*ref_b).b == 25); +} + +struct Outer { + inner: MyStruct, +} + +fn nested_struct_aliases() { + let mut var = Outer { inner: MyStruct { a: 0, b: 0 } }; + + let ref_outer = &mut var; + let ref_inner = &mut ref_outer.inner; + + (*ref_outer).inner.a = 5; + (*ref_inner).b = 10; + + assert(var.inner.a == 5); + assert(var.inner.b == 10); + assert((*ref_outer).inner.a == 5); + assert((*ref_outer).inner.b == 10); + assert((*ref_inner).a == 5); + assert((*ref_inner).b == 10); +} + +fn nested_struct_multi_field_different_aliases_in_loop() { + let mut var = Outer { inner: MyStruct { a: 0, b: 0 } }; + let ref_outer = &mut var; + let ref_inner = &mut var.inner; + + for _ in 0..3 { + (*ref_outer).inner.a += 2; + (*ref_inner).a += 3; + (*ref_outer).inner.b += 1; + (*ref_inner).b += 2; + } + + assert(var.inner.a == 15); + assert(var.inner.b == 9); + assert((*ref_outer).inner.a == 15); + assert((*ref_outer).inner.b == 9); + assert((*ref_inner).a == 15); + assert((*ref_inner).b == 9); +} + +fn nested_struct_aliases_in_array() { + let mut var = Outer { inner: MyStruct { a: 0, b: 0 } }; + + let ref = &mut &mut &mut var; + + let mut array = [ref, ref]; + + // Update the same inner field `a` through both deep aliases + (**array[0]).inner.a += 5; + (**array[1]).inner.a += 2; + + assert(var.inner.a == 7); + assert((***ref).inner.a == 7); + assert((**array[0]).inner.a == 7); + assert((**array[1]).inner.a == 7); + + assert(var.inner.b == 0); +} + fn struct_field_refs_across_blocks(mut my_struct: MyStruct) -> [Field; 1] { [compute_dummy_hash(my_struct.a, my_struct.b, 20)] } diff --git a/test_programs/execution_success/references/src/main.nr b/test_programs/execution_success/references/src/main.nr index 65d70dc4a5f..cffe7aa2a50 100644 --- a/test_programs/execution_success/references/src/main.nr +++ b/test_programs/execution_success/references/src/main.nr @@ -31,6 +31,9 @@ fn main(mut x: Field) { regression_2218_else(x, 3); regression_2218_loop(x, 10); regression_2560(s_ref); + nested_struct_aliases(x, 10); + assert_eq(x, 3); + nested_struct_aliases(x, 3); } fn add1(x: &mut Field) { @@ -242,3 +245,65 @@ fn regression_2218_loop(x: Field, y: Field) { fn regression_2560(s_ref: &mut S) { assert(s_ref.get_y() == 7); } + +struct MyStruct { + a: Field, + b: u32, +} + +struct Outer { + inner: MyStruct, +} + +fn nested_struct_aliases(x: Field, y: Field) { + let mut var = Outer { inner: MyStruct { a: 0, b: 0 } }; + let ref_outer = &mut var; + let ref_inner1 = &mut ref_outer.inner; + let ref_inner2 = &mut var.inner; + + if x != y { + (*ref_inner1).a = 5; + (*ref_inner1).b = 7; + (*ref_inner2).a = 3; + (*ref_inner2).b = 10; + + for _ in 0..3 { + (*ref_inner1).a += 1; + (*ref_inner1).b += 2; + (*ref_inner2).a += 2; + (*ref_inner2).b += 4; + } + } else { + (*ref_inner2).a = 20; + (*ref_inner2).b = 15; + (*ref_inner1).a = 25; + (*ref_inner1).b = 30; + + for _ in 0..3 { + (*ref_inner2).a += 5; + (*ref_inner2).b += 3; + (*ref_inner1).a += 4; + (*ref_inner1).b += 10; + } + } + + if x != y { + assert(var.inner.a == 12); + assert(var.inner.b == 28); + assert(ref_inner1.a == 12); + assert(ref_inner1.b == 28); + assert(ref_inner2.a == 12); + assert(ref_inner2.b == 28); + assert(ref_outer.inner.a == 12); + assert(ref_outer.inner.b == 28); + } else { + assert(var.inner.a == 52); + assert(var.inner.b == 69); + assert(ref_inner1.a == 52); + assert(ref_inner1.b == 69); + assert(ref_inner2.a == 52); + assert(ref_inner2.b == 69); + assert(ref_outer.inner.a == 52); + assert(ref_outer.inner.b == 69); + } +} diff --git a/tooling/nargo_cli/tests/snapshots/compile_success_empty/references_aliasing/execute__tests__expanded.snap b/tooling/nargo_cli/tests/snapshots/compile_success_empty/references_aliasing/execute__tests__expanded.snap index 4520f7a2e39..65474916233 100644 --- a/tooling/nargo_cli/tests/snapshots/compile_success_empty/references_aliasing/execute__tests__expanded.snap +++ b/tooling/nargo_cli/tests/snapshots/compile_success_empty/references_aliasing/execute__tests__expanded.snap @@ -7,8 +7,22 @@ fn main() { let mut xref: &mut Field = &mut x; increment(xref); assert(*xref == 101_Field); + let mut x_three_refs: &mut &mut &mut Field = &mut &mut &mut x; + increment_deeper_ref(x_three_refs); + assert(***x_three_refs == 102_Field); regression_2445(); + regression_2445_deeper_ref(); + struct_alias_in_array(); single_alias_inside_loop(); + deeper_ref_in_loop(); + struct_alias_in_loop(); + struct_multi_field_alias(); + struct_multi_field_alias_in_loop(); + struct_multi_field_different_aliases(); + struct_multi_field_different_aliases_in_loop(); + nested_struct_aliases(); + nested_struct_multi_field_different_aliases_in_loop(); + nested_struct_aliases_in_array(); assert(5_Field == struct_field_refs_across_blocks(MyStruct { a: 5_Field, b: 10_u32 })[0_u32]); } @@ -16,6 +30,10 @@ fn increment(mut r: &mut Field) { *r = *r + 1_Field; } +fn increment_deeper_ref(mut r: &mut &mut &mut Field) { + ***r = ***r + 1_Field; +} + fn regression_2445() { let mut var: Field = 0_Field; let ref: &mut &mut Field = &mut &mut var; @@ -28,6 +46,35 @@ fn regression_2445() { assert(**array[1_u32] == 2_Field); } +fn regression_2445_deeper_ref() { + let mut var: Field = 0_Field; + let ref: &mut &mut &mut Field = &mut &mut &mut var; + let mut array: [&mut &mut &mut Field; 2] = [ref, ref]; + ***array[0_u32] = 1_Field; + ***array[1_u32] = 2_Field; + assert(var == 2_Field); + assert(***ref == 2_Field); + assert(***array[0_u32] == 2_Field); + assert(***array[1_u32] == 2_Field); +} + +struct Foo { + inner: u32, +} + +fn struct_alias_in_array() { + let mut var: Foo = Foo { inner: 0_u32 }; + let ref: &mut &mut Foo = &mut &mut var; + let mut array: [&mut &mut Foo; 2] = [ref, ref]; + assert((**array[0_u32]).inner == 0_u32); + (**array[0_u32]).inner = 1_u32; + (**array[1_u32]).inner = 2_u32; + assert(var.inner == 2_u32); + assert((**ref).inner == 2_u32); + assert((**array[0_u32]).inner == 2_u32); + assert((**array[1_u32]).inner == 2_u32); +} + fn single_alias_inside_loop() { let mut var: Field = 0_Field; let ref: &mut &mut Field = &mut &mut var; @@ -38,11 +85,139 @@ fn single_alias_inside_loop() { assert(**ref == 2_Field); } +fn deeper_ref_in_loop() { + let mut var: Field = 0_Field; + let ref: &mut &mut &mut Field = &mut &mut &mut var; + for _ in 0_u32..1_u32 { + ***ref = 2_Field; + } + assert(var == 2_Field); + assert(***ref == 2_Field); +} + +fn struct_alias_in_loop() { + let mut var: Foo = Foo { inner: 0_u32 }; + let ref: &mut &mut Foo = &mut &mut var; + for _ in 0_u32..1_u32 { + (**ref).inner = 1_u32; + (**ref).inner = 2_u32; + } + assert(var.inner == 2_u32); + assert((**ref).inner == 2_u32); +} + struct MyStruct { a: Field, b: u32, } +fn struct_multi_field_alias() { + let mut var: MyStruct = MyStruct { a: 0_Field, b: 10_u32 }; + let ref: &mut &mut MyStruct = &mut &mut var; + (**ref).a = 1_Field; + (**ref).b = 20_u32; + assert(var.a == 1_Field); + assert(var.b == 20_u32); + assert((**ref).a == 1_Field); + assert((**ref).b == 20_u32); +} + +fn struct_multi_field_alias_in_loop() { + let mut var: MyStruct = MyStruct { a: 0_Field, b: 0_u32 }; + let ref: &mut &mut MyStruct = &mut &mut var; + for _ in 0_u32..1_u32 { + (**ref).a = (**ref).a + 1_Field; + (**ref).b = (**ref).b + 2_u32; + } + assert(var.a == 1_Field); + assert(var.b == 2_u32); + assert((**ref).a == 1_Field); + assert((**ref).b == 2_u32); +} + +fn struct_multi_field_different_aliases_in_loop() { + let mut var: MyStruct = MyStruct { a: 0_Field, b: 0_u32 }; + let ref_a: &mut MyStruct = &mut var; + let ref_b: &mut MyStruct = &mut var; + for _ in 0_u32..3_u32 { + (*ref_a).a = (*ref_a).a + 2_Field; + (*ref_b).a = (*ref_b).a + 3_Field; + (*ref_a).b = (*ref_a).b + 1_u32; + (*ref_b).b = (*ref_b).b + 2_u32; + } + assert(var.a == 15_Field); + assert(var.b == 9_u32); + assert((*ref_a).a == 15_Field); + assert((*ref_a).b == 9_u32); + assert((*ref_b).a == 15_Field); + assert((*ref_b).b == 9_u32); +} + +fn struct_multi_field_different_aliases() { + let mut var: MyStruct = MyStruct { a: 0_Field, b: 0_u32 }; + let ref_a: &mut MyStruct = &mut var; + let ref_b: &mut MyStruct = &mut var; + (*ref_a).a = 10_Field; + (*ref_a).b = 20_u32; + (*ref_b).a = (*ref_b).a + 5_Field; + (*ref_b).b = (*ref_b).b + 5_u32; + assert(var.a == 15_Field); + assert(var.b == 25_u32); + assert((*ref_a).a == 15_Field); + assert((*ref_a).b == 25_u32); + assert((*ref_b).a == 15_Field); + assert((*ref_b).b == 25_u32); +} + +struct Outer { + inner: MyStruct, +} + +fn nested_struct_aliases() { + let mut var: Outer = Outer { inner: MyStruct { a: 0_Field, b: 0_u32 } }; + let ref_outer: &mut Outer = &mut var; + let ref_inner: &mut MyStruct = &mut ref_outer.inner; + (*ref_outer).inner.a = 5_Field; + (*ref_inner).b = 10_u32; + assert(var.inner.a == 5_Field); + assert(var.inner.b == 10_u32); + assert((*ref_outer).inner.a == 5_Field); + assert((*ref_outer).inner.b == 10_u32); + assert((*ref_inner).a == 5_Field); + assert((*ref_inner).b == 10_u32); +} + +fn nested_struct_multi_field_different_aliases_in_loop() { + let mut var: Outer = Outer { inner: MyStruct { a: 0_Field, b: 0_u32 } }; + let ref_outer: &mut Outer = &mut var; + let ref_inner: &mut MyStruct = &mut var.inner; + for _ in 0_u32..3_u32 { + (*ref_outer).inner.a = (*ref_outer).inner.a + 2_Field; + (*ref_inner).a = (*ref_inner).a + 3_Field; + (*ref_outer).inner.b = (*ref_outer).inner.b + 1_u32; + (*ref_inner).b = (*ref_inner).b + 2_u32; + } + assert(var.inner.a == 15_Field); + assert(var.inner.b == 9_u32); + assert((*ref_outer).inner.a == 15_Field); + assert((*ref_outer).inner.b == 9_u32); + assert((*ref_inner).a == 15_Field); + assert((*ref_inner).b == 9_u32); +} + +fn nested_struct_aliases_in_array() { + let mut var: Outer = Outer { inner: MyStruct { a: 0_Field, b: 0_u32 } }; + let ref: &mut &mut &mut Outer = &mut &mut &mut var; + let mut array: [&mut &mut &mut Outer; 2] = [ref, ref]; + (**array[0_u32]).inner.a = (**array[0_u32]).inner.a + 5_Field; + (**array[1_u32]).inner.a = (**array[1_u32]).inner.a + 2_Field; + assert(var.inner.a == 7_Field); + assert((***ref).inner.a == 7_Field); + assert((**array[0_u32]).inner.a == 7_Field); + assert((**array[1_u32]).inner.a == 7_Field); + assert(var.inner.b == 0_u32); +} + fn struct_field_refs_across_blocks(mut my_struct: MyStruct) -> [Field; 1] { [compute_dummy_hash(my_struct.a, my_struct.b, 20_u32)] } diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/references/execute__tests__expanded.snap b/tooling/nargo_cli/tests/snapshots/execution_success/references/execute__tests__expanded.snap index d5195dab7dc..30f70f56395 100644 --- a/tooling/nargo_cli/tests/snapshots/execution_success/references/execute__tests__expanded.snap +++ b/tooling/nargo_cli/tests/snapshots/execution_success/references/execute__tests__expanded.snap @@ -31,6 +31,9 @@ fn main(mut x: Field) { regression_2218_else(x, 3_Field); regression_2218_loop(x, 10_Field); regression_2560(s_ref); + nested_struct_aliases(x, 10_Field); + assert(x == 3_Field); + nested_struct_aliases(x, 3_Field); } fn add1(x: &mut Field) { @@ -224,3 +227,61 @@ fn regression_2218_loop(x: Field, y: Field) { fn regression_2560(s_ref: &mut S) { assert(s_ref.get_y() == 7_Field); } + +struct MyStruct { + a: Field, + b: u32, +} + +struct Outer { + inner: MyStruct, +} + +fn nested_struct_aliases(x: Field, y: Field) { + let mut var: Outer = Outer { inner: MyStruct { a: 0_Field, b: 0_u32 } }; + let ref_outer: &mut Outer = &mut var; + let ref_inner1: &mut MyStruct = &mut ref_outer.inner; + let ref_inner2: &mut MyStruct = &mut var.inner; + if x != y { + (*ref_inner1).a = 5_Field; + (*ref_inner1).b = 7_u32; + (*ref_inner2).a = 3_Field; + (*ref_inner2).b = 10_u32; + for _ in 0_u32..3_u32 { + (*ref_inner1).a = (*ref_inner1).a + 1_Field; + (*ref_inner1).b = (*ref_inner1).b + 2_u32; + (*ref_inner2).a = (*ref_inner2).a + 2_Field; + (*ref_inner2).b = (*ref_inner2).b + 4_u32; + } + } else { + (*ref_inner2).a = 20_Field; + (*ref_inner2).b = 15_u32; + (*ref_inner1).a = 25_Field; + (*ref_inner1).b = 30_u32; + for _ in 0_u32..3_u32 { + (*ref_inner2).a = (*ref_inner2).a + 5_Field; + (*ref_inner2).b = (*ref_inner2).b + 3_u32; + (*ref_inner1).a = (*ref_inner1).a + 4_Field; + (*ref_inner1).b = (*ref_inner1).b + 10_u32; + } + }; + if x != y { + assert(var.inner.a == 12_Field); + assert(var.inner.b == 28_u32); + assert(ref_inner1.a == 12_Field); + assert(ref_inner1.b == 28_u32); + assert(ref_inner2.a == 12_Field); + assert(ref_inner2.b == 28_u32); + assert(ref_outer.inner.a == 12_Field); + assert(ref_outer.inner.b == 28_u32); + } else { + assert(var.inner.a == 52_Field); + assert(var.inner.b == 69_u32); + assert(ref_inner1.a == 52_Field); + assert(ref_inner1.b == 69_u32); + assert(ref_inner2.a == 52_Field); + assert(ref_inner2.b == 69_u32); + assert(ref_outer.inner.a == 52_Field); + assert(ref_outer.inner.b == 69_u32); + } +} diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/references/execute__tests__force_brillig_false_inliner_-9223372036854775808.snap b/tooling/nargo_cli/tests/snapshots/execution_success/references/execute__tests__force_brillig_false_inliner_-9223372036854775808.snap index 4c239c5c2dc..ee05806bd41 100644 --- a/tooling/nargo_cli/tests/snapshots/execution_success/references/execute__tests__force_brillig_false_inliner_-9223372036854775808.snap +++ b/tooling/nargo_cli/tests/snapshots/execution_success/references/execute__tests__force_brillig_false_inliner_-9223372036854775808.snap @@ -26,10 +26,10 @@ expression: artifact "return value indices : []", "EXPR [ (1, _0) -2 ]" ], - "debug_symbols": "fZBNCoMwEIXvMmsXpipYr1KKxDhKICRhTApFvHtHiagLu5qfN98beDP02MWx1XZwEzSvGTrSxuixNU7JoJ3l7bxksI9tIERewUlnyktCG6Cx0ZgMPtLE7Wjy0m41SGI1zwBtz5UNB21w7ZbsoPN79FEntjzg6kqLe1qIUiSe2/rO4c//qkh89bzQb56k0nTJC3JoimU1Iy07gynDIVp1ijR8/a7soXtyCvtIuNptGj/4AQ==", + "debug_symbols": "fZBNCoMwEIXvMmsXGmtpvUopEuMogZCEMSkU8e4dJaIu7Gp+3nxv4E3QYRuHRtvejVC/JmhJG6OHxjglg3aWt9OcwTY2gRB5BQedKS8JbYDaRmMy+EgT16PRS7vWIInVPAO0HVc27LXBpZuznc6vUfFI7G2HqzNdXNOFEM/EF6K8Xzn8+V+Via+eJ/rNk1SaTnlBDnU5L2akZWswZdhHqw6Rhq/flC10T05hFwkXu1XjBz8=", "file_map": { "50": { - "source": "fn main(mut x: Field) {\n add1(&mut x);\n assert(x == 3);\n let mut s = S { y: x };\n s.add2();\n assert(s.y == 5);\n // Regression for #1946: Method resolution error when calling &mut methods with a variable of type &mut T\n let s_ref = &mut s;\n s_ref.add2();\n assert(s.y == 7);\n // Test that normal mutable variables are still copied\n let mut a = 0;\n mutate_copy(a);\n assert(a == 0);\n // Test something 3 allocations deep\n let mut nested_allocations = Nested { y: &mut &mut 0 };\n add1(*nested_allocations.y);\n assert(**nested_allocations.y == 1);\n // Test nested struct allocations with a mutable reference to an array.\n let mut c = C { foo: 0, bar: &mut C2 { array: &mut [1, 2] } };\n *c.bar.array = [3, 4];\n assert(*c.bar.array == [3, 4]);\n regression_1887();\n regression_2054();\n regression_2030();\n regression_2255();\n regression_6443();\n assert(x == 3);\n regression_2218_if_inner_if(x, 10);\n regression_2218_if_inner_else(20, x);\n regression_2218_else(x, 3);\n regression_2218_loop(x, 10);\n regression_2560(s_ref);\n}\n\nfn add1(x: &mut Field) {\n *x += 1;\n}\n\nstruct S {\n y: Field,\n}\n\nstruct Nested {\n y: &mut &mut Field,\n}\n\nstruct C {\n foo: Field,\n bar: &mut C2,\n}\n\nstruct C2 {\n array: &mut [Field; 2],\n}\n\nimpl S {\n fn add2(&mut self) {\n self.y += 2;\n }\n\n fn get_y(self) -> Field {\n self.y\n }\n}\n\nfn mutate_copy(mut a: Field) {\n a = 7;\n}\n// Previously the `foo.bar` in `foo.bar.mutate()` would insert an automatic dereference\n// of `foo` which caused the method to wrongly be mutating a copy of bar rather than the original.\nfn regression_1887() {\n let foo = &mut Foo { bar: Bar { x: 0 } };\n foo.bar.mutate();\n assert(foo.bar.x == 32);\n}\n\nstruct Foo {\n bar: Bar,\n}\nstruct Bar {\n x: Field,\n}\n\nimpl Bar {\n fn mutate(&mut self) {\n self.x = 32;\n }\n}\n// Ensure that mutating a variable does not also mutate its copy\nfn regression_2054() {\n let mut x = 2;\n let z = x;\n\n x += 1;\n assert(z == 2);\n}\n// The compiler was still trying to convert an LValue from an array of structs to struct of arrays indexing,\n// even though this conversion was mostly removed elsewhere.\nfn regression_2030() {\n let ref = &mut 0;\n let mut array = [ref, ref];\n let _ = *array[0];\n *array[0] = 1;\n}\n\n// The `mut x: &mut ...` caught a bug handling lvalues where a double-dereference would occur internally\n// in one step rather than being tracked by two separate steps. This lead to assigning the 1 value to the\n// incorrect outer `mut` reference rather than the correct `&mut` reference.\nfn regression_2255() {\n let x = &mut 0;\n regression_2255_helper(x);\n assert(*x == 1);\n}\n\nfn regression_2255_helper(mut x: &mut Field) {\n *x = 1;\n}\n\n// Similar to `regression_2255` but without the double-dereferencing.\n// The test checks that `mem2reg` does not eliminate storing to a reference passed as a parameter.\nfn regression_6443() {\n let x = &mut 0;\n regression_6443_helper(x);\n assert(*x == 1);\n}\n\nfn regression_6443_helper(x: &mut Field) {\n *x = 1;\n}\n\nfn regression_2218(x: Field, y: Field) -> Field {\n let q = &mut &mut 0;\n let q1 = *q;\n let q2 = *q;\n\n if x != y {\n *q1 = 1;\n // Make sure that we correct load reference aliases through multiple blocks\n if x != 20 {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n } else {\n *q2 = 15;\n assert(*q1 == 15);\n }\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n // Have to assign value to return it\n let value = *q1;\n value\n}\n\nfn regression_2218_if_inner_if(x: Field, y: Field) {\n let value = regression_2218(x, y);\n assert(value == 2);\n}\n\nfn regression_2218_if_inner_else(x: Field, y: Field) {\n let value = regression_2218(x, y);\n assert(value == 15);\n}\n\nfn regression_2218_else(x: Field, y: Field) {\n let value = regression_2218(x, y);\n assert(value == 20);\n}\n\nfn regression_2218_loop(x: Field, y: Field) {\n let q = &mut &mut 0;\n let q1 = *q;\n let q2 = *q;\n\n for _ in 0..1 {\n if x != y {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n }\n assert(*q1 == 2);\n\n for _ in 0..1 {\n for _ in 0..5 {\n if x != y {\n *q1 = 1;\n // Make sure that we correct load reference aliases through multiple blocks\n if x != 20 {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n }\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n }\n if x != y {\n *q1 = 1;\n for _ in 0..5 {\n // Make sure that we correct load reference aliases through multiple blocks\n if x != 20 {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n }\n }\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n }\n assert(*q1 == 2);\n\n if x != y {\n for _ in 0..5 {\n if x != y {\n *q1 = 1;\n // Make sure that we correct load reference aliases through multiple blocks\n if x != 20 {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n }\n }\n }\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n assert(*q1 == 2);\n}\n// This is more a feature test than a proper regression.\n// Before, we never automatically dereferenced objects in method calls to their value types.\n// Now, we insert as many `*` as necessary to get to `S`.\nfn regression_2560(s_ref: &mut S) {\n assert(s_ref.get_y() == 7);\n}\n", + "source": "fn main(mut x: Field) {\n add1(&mut x);\n assert(x == 3);\n let mut s = S { y: x };\n s.add2();\n assert(s.y == 5);\n // Regression for #1946: Method resolution error when calling &mut methods with a variable of type &mut T\n let s_ref = &mut s;\n s_ref.add2();\n assert(s.y == 7);\n // Test that normal mutable variables are still copied\n let mut a = 0;\n mutate_copy(a);\n assert(a == 0);\n // Test something 3 allocations deep\n let mut nested_allocations = Nested { y: &mut &mut 0 };\n add1(*nested_allocations.y);\n assert(**nested_allocations.y == 1);\n // Test nested struct allocations with a mutable reference to an array.\n let mut c = C { foo: 0, bar: &mut C2 { array: &mut [1, 2] } };\n *c.bar.array = [3, 4];\n assert(*c.bar.array == [3, 4]);\n regression_1887();\n regression_2054();\n regression_2030();\n regression_2255();\n regression_6443();\n assert(x == 3);\n regression_2218_if_inner_if(x, 10);\n regression_2218_if_inner_else(20, x);\n regression_2218_else(x, 3);\n regression_2218_loop(x, 10);\n regression_2560(s_ref);\n nested_struct_aliases(x, 10);\n assert_eq(x, 3);\n nested_struct_aliases(x, 3);\n}\n\nfn add1(x: &mut Field) {\n *x += 1;\n}\n\nstruct S {\n y: Field,\n}\n\nstruct Nested {\n y: &mut &mut Field,\n}\n\nstruct C {\n foo: Field,\n bar: &mut C2,\n}\n\nstruct C2 {\n array: &mut [Field; 2],\n}\n\nimpl S {\n fn add2(&mut self) {\n self.y += 2;\n }\n\n fn get_y(self) -> Field {\n self.y\n }\n}\n\nfn mutate_copy(mut a: Field) {\n a = 7;\n}\n// Previously the `foo.bar` in `foo.bar.mutate()` would insert an automatic dereference\n// of `foo` which caused the method to wrongly be mutating a copy of bar rather than the original.\nfn regression_1887() {\n let foo = &mut Foo { bar: Bar { x: 0 } };\n foo.bar.mutate();\n assert(foo.bar.x == 32);\n}\n\nstruct Foo {\n bar: Bar,\n}\nstruct Bar {\n x: Field,\n}\n\nimpl Bar {\n fn mutate(&mut self) {\n self.x = 32;\n }\n}\n// Ensure that mutating a variable does not also mutate its copy\nfn regression_2054() {\n let mut x = 2;\n let z = x;\n\n x += 1;\n assert(z == 2);\n}\n// The compiler was still trying to convert an LValue from an array of structs to struct of arrays indexing,\n// even though this conversion was mostly removed elsewhere.\nfn regression_2030() {\n let ref = &mut 0;\n let mut array = [ref, ref];\n let _ = *array[0];\n *array[0] = 1;\n}\n\n// The `mut x: &mut ...` caught a bug handling lvalues where a double-dereference would occur internally\n// in one step rather than being tracked by two separate steps. This lead to assigning the 1 value to the\n// incorrect outer `mut` reference rather than the correct `&mut` reference.\nfn regression_2255() {\n let x = &mut 0;\n regression_2255_helper(x);\n assert(*x == 1);\n}\n\nfn regression_2255_helper(mut x: &mut Field) {\n *x = 1;\n}\n\n// Similar to `regression_2255` but without the double-dereferencing.\n// The test checks that `mem2reg` does not eliminate storing to a reference passed as a parameter.\nfn regression_6443() {\n let x = &mut 0;\n regression_6443_helper(x);\n assert(*x == 1);\n}\n\nfn regression_6443_helper(x: &mut Field) {\n *x = 1;\n}\n\nfn regression_2218(x: Field, y: Field) -> Field {\n let q = &mut &mut 0;\n let q1 = *q;\n let q2 = *q;\n\n if x != y {\n *q1 = 1;\n // Make sure that we correct load reference aliases through multiple blocks\n if x != 20 {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n } else {\n *q2 = 15;\n assert(*q1 == 15);\n }\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n // Have to assign value to return it\n let value = *q1;\n value\n}\n\nfn regression_2218_if_inner_if(x: Field, y: Field) {\n let value = regression_2218(x, y);\n assert(value == 2);\n}\n\nfn regression_2218_if_inner_else(x: Field, y: Field) {\n let value = regression_2218(x, y);\n assert(value == 15);\n}\n\nfn regression_2218_else(x: Field, y: Field) {\n let value = regression_2218(x, y);\n assert(value == 20);\n}\n\nfn regression_2218_loop(x: Field, y: Field) {\n let q = &mut &mut 0;\n let q1 = *q;\n let q2 = *q;\n\n for _ in 0..1 {\n if x != y {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n }\n assert(*q1 == 2);\n\n for _ in 0..1 {\n for _ in 0..5 {\n if x != y {\n *q1 = 1;\n // Make sure that we correct load reference aliases through multiple blocks\n if x != 20 {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n }\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n }\n if x != y {\n *q1 = 1;\n for _ in 0..5 {\n // Make sure that we correct load reference aliases through multiple blocks\n if x != 20 {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n }\n }\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n }\n assert(*q1 == 2);\n\n if x != y {\n for _ in 0..5 {\n if x != y {\n *q1 = 1;\n // Make sure that we correct load reference aliases through multiple blocks\n if x != 20 {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n }\n }\n }\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n assert(*q1 == 2);\n}\n// This is more a feature test than a proper regression.\n// Before, we never automatically dereferenced objects in method calls to their value types.\n// Now, we insert as many `*` as necessary to get to `S`.\nfn regression_2560(s_ref: &mut S) {\n assert(s_ref.get_y() == 7);\n}\n\nstruct MyStruct {\n a: Field,\n b: u32,\n}\n\nstruct Outer {\n inner: MyStruct,\n}\n\nfn nested_struct_aliases(x: Field, y: Field) {\n let mut var = Outer { inner: MyStruct { a: 0, b: 0 } };\n let ref_outer = &mut var;\n let ref_inner1 = &mut ref_outer.inner;\n let ref_inner2 = &mut var.inner;\n\n if x != y {\n (*ref_inner1).a = 5;\n (*ref_inner1).b = 7;\n (*ref_inner2).a = 3;\n (*ref_inner2).b = 10;\n\n for _ in 0..3 {\n (*ref_inner1).a += 1;\n (*ref_inner1).b += 2;\n (*ref_inner2).a += 2;\n (*ref_inner2).b += 4;\n }\n } else {\n (*ref_inner2).a = 20;\n (*ref_inner2).b = 15;\n (*ref_inner1).a = 25;\n (*ref_inner1).b = 30;\n\n for _ in 0..3 {\n (*ref_inner2).a += 5;\n (*ref_inner2).b += 3;\n (*ref_inner1).a += 4;\n (*ref_inner1).b += 10;\n }\n }\n\n if x != y {\n assert(var.inner.a == 12);\n assert(var.inner.b == 28);\n assert(ref_inner1.a == 12);\n assert(ref_inner1.b == 28);\n assert(ref_inner2.a == 12);\n assert(ref_inner2.b == 28);\n assert(ref_outer.inner.a == 12);\n assert(ref_outer.inner.b == 28);\n } else {\n assert(var.inner.a == 52);\n assert(var.inner.b == 69);\n assert(ref_inner1.a == 52);\n assert(ref_inner1.b == 69);\n assert(ref_inner2.a == 52);\n assert(ref_inner2.b == 69);\n assert(ref_outer.inner.a == 52);\n assert(ref_outer.inner.b == 69);\n }\n}\n", "path": "" } }, diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/references/execute__tests__force_brillig_false_inliner_0.snap b/tooling/nargo_cli/tests/snapshots/execution_success/references/execute__tests__force_brillig_false_inliner_0.snap index 4c239c5c2dc..ee05806bd41 100644 --- a/tooling/nargo_cli/tests/snapshots/execution_success/references/execute__tests__force_brillig_false_inliner_0.snap +++ b/tooling/nargo_cli/tests/snapshots/execution_success/references/execute__tests__force_brillig_false_inliner_0.snap @@ -26,10 +26,10 @@ expression: artifact "return value indices : []", "EXPR [ (1, _0) -2 ]" ], - "debug_symbols": "fZBNCoMwEIXvMmsXpipYr1KKxDhKICRhTApFvHtHiagLu5qfN98beDP02MWx1XZwEzSvGTrSxuixNU7JoJ3l7bxksI9tIERewUlnyktCG6Cx0ZgMPtLE7Wjy0m41SGI1zwBtz5UNB21w7ZbsoPN79FEntjzg6kqLe1qIUiSe2/rO4c//qkh89bzQb56k0nTJC3JoimU1Iy07gynDIVp1ijR8/a7soXtyCvtIuNptGj/4AQ==", + "debug_symbols": "fZBNCoMwEIXvMmsXGmtpvUopEuMogZCEMSkU8e4dJaIu7Gp+3nxv4E3QYRuHRtvejVC/JmhJG6OHxjglg3aWt9OcwTY2gRB5BQedKS8JbYDaRmMy+EgT16PRS7vWIInVPAO0HVc27LXBpZuznc6vUfFI7G2HqzNdXNOFEM/EF6K8Xzn8+V+Via+eJ/rNk1SaTnlBDnU5L2akZWswZdhHqw6Rhq/flC10T05hFwkXu1XjBz8=", "file_map": { "50": { - "source": "fn main(mut x: Field) {\n add1(&mut x);\n assert(x == 3);\n let mut s = S { y: x };\n s.add2();\n assert(s.y == 5);\n // Regression for #1946: Method resolution error when calling &mut methods with a variable of type &mut T\n let s_ref = &mut s;\n s_ref.add2();\n assert(s.y == 7);\n // Test that normal mutable variables are still copied\n let mut a = 0;\n mutate_copy(a);\n assert(a == 0);\n // Test something 3 allocations deep\n let mut nested_allocations = Nested { y: &mut &mut 0 };\n add1(*nested_allocations.y);\n assert(**nested_allocations.y == 1);\n // Test nested struct allocations with a mutable reference to an array.\n let mut c = C { foo: 0, bar: &mut C2 { array: &mut [1, 2] } };\n *c.bar.array = [3, 4];\n assert(*c.bar.array == [3, 4]);\n regression_1887();\n regression_2054();\n regression_2030();\n regression_2255();\n regression_6443();\n assert(x == 3);\n regression_2218_if_inner_if(x, 10);\n regression_2218_if_inner_else(20, x);\n regression_2218_else(x, 3);\n regression_2218_loop(x, 10);\n regression_2560(s_ref);\n}\n\nfn add1(x: &mut Field) {\n *x += 1;\n}\n\nstruct S {\n y: Field,\n}\n\nstruct Nested {\n y: &mut &mut Field,\n}\n\nstruct C {\n foo: Field,\n bar: &mut C2,\n}\n\nstruct C2 {\n array: &mut [Field; 2],\n}\n\nimpl S {\n fn add2(&mut self) {\n self.y += 2;\n }\n\n fn get_y(self) -> Field {\n self.y\n }\n}\n\nfn mutate_copy(mut a: Field) {\n a = 7;\n}\n// Previously the `foo.bar` in `foo.bar.mutate()` would insert an automatic dereference\n// of `foo` which caused the method to wrongly be mutating a copy of bar rather than the original.\nfn regression_1887() {\n let foo = &mut Foo { bar: Bar { x: 0 } };\n foo.bar.mutate();\n assert(foo.bar.x == 32);\n}\n\nstruct Foo {\n bar: Bar,\n}\nstruct Bar {\n x: Field,\n}\n\nimpl Bar {\n fn mutate(&mut self) {\n self.x = 32;\n }\n}\n// Ensure that mutating a variable does not also mutate its copy\nfn regression_2054() {\n let mut x = 2;\n let z = x;\n\n x += 1;\n assert(z == 2);\n}\n// The compiler was still trying to convert an LValue from an array of structs to struct of arrays indexing,\n// even though this conversion was mostly removed elsewhere.\nfn regression_2030() {\n let ref = &mut 0;\n let mut array = [ref, ref];\n let _ = *array[0];\n *array[0] = 1;\n}\n\n// The `mut x: &mut ...` caught a bug handling lvalues where a double-dereference would occur internally\n// in one step rather than being tracked by two separate steps. This lead to assigning the 1 value to the\n// incorrect outer `mut` reference rather than the correct `&mut` reference.\nfn regression_2255() {\n let x = &mut 0;\n regression_2255_helper(x);\n assert(*x == 1);\n}\n\nfn regression_2255_helper(mut x: &mut Field) {\n *x = 1;\n}\n\n// Similar to `regression_2255` but without the double-dereferencing.\n// The test checks that `mem2reg` does not eliminate storing to a reference passed as a parameter.\nfn regression_6443() {\n let x = &mut 0;\n regression_6443_helper(x);\n assert(*x == 1);\n}\n\nfn regression_6443_helper(x: &mut Field) {\n *x = 1;\n}\n\nfn regression_2218(x: Field, y: Field) -> Field {\n let q = &mut &mut 0;\n let q1 = *q;\n let q2 = *q;\n\n if x != y {\n *q1 = 1;\n // Make sure that we correct load reference aliases through multiple blocks\n if x != 20 {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n } else {\n *q2 = 15;\n assert(*q1 == 15);\n }\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n // Have to assign value to return it\n let value = *q1;\n value\n}\n\nfn regression_2218_if_inner_if(x: Field, y: Field) {\n let value = regression_2218(x, y);\n assert(value == 2);\n}\n\nfn regression_2218_if_inner_else(x: Field, y: Field) {\n let value = regression_2218(x, y);\n assert(value == 15);\n}\n\nfn regression_2218_else(x: Field, y: Field) {\n let value = regression_2218(x, y);\n assert(value == 20);\n}\n\nfn regression_2218_loop(x: Field, y: Field) {\n let q = &mut &mut 0;\n let q1 = *q;\n let q2 = *q;\n\n for _ in 0..1 {\n if x != y {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n }\n assert(*q1 == 2);\n\n for _ in 0..1 {\n for _ in 0..5 {\n if x != y {\n *q1 = 1;\n // Make sure that we correct load reference aliases through multiple blocks\n if x != 20 {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n }\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n }\n if x != y {\n *q1 = 1;\n for _ in 0..5 {\n // Make sure that we correct load reference aliases through multiple blocks\n if x != 20 {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n }\n }\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n }\n assert(*q1 == 2);\n\n if x != y {\n for _ in 0..5 {\n if x != y {\n *q1 = 1;\n // Make sure that we correct load reference aliases through multiple blocks\n if x != 20 {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n }\n }\n }\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n assert(*q1 == 2);\n}\n// This is more a feature test than a proper regression.\n// Before, we never automatically dereferenced objects in method calls to their value types.\n// Now, we insert as many `*` as necessary to get to `S`.\nfn regression_2560(s_ref: &mut S) {\n assert(s_ref.get_y() == 7);\n}\n", + "source": "fn main(mut x: Field) {\n add1(&mut x);\n assert(x == 3);\n let mut s = S { y: x };\n s.add2();\n assert(s.y == 5);\n // Regression for #1946: Method resolution error when calling &mut methods with a variable of type &mut T\n let s_ref = &mut s;\n s_ref.add2();\n assert(s.y == 7);\n // Test that normal mutable variables are still copied\n let mut a = 0;\n mutate_copy(a);\n assert(a == 0);\n // Test something 3 allocations deep\n let mut nested_allocations = Nested { y: &mut &mut 0 };\n add1(*nested_allocations.y);\n assert(**nested_allocations.y == 1);\n // Test nested struct allocations with a mutable reference to an array.\n let mut c = C { foo: 0, bar: &mut C2 { array: &mut [1, 2] } };\n *c.bar.array = [3, 4];\n assert(*c.bar.array == [3, 4]);\n regression_1887();\n regression_2054();\n regression_2030();\n regression_2255();\n regression_6443();\n assert(x == 3);\n regression_2218_if_inner_if(x, 10);\n regression_2218_if_inner_else(20, x);\n regression_2218_else(x, 3);\n regression_2218_loop(x, 10);\n regression_2560(s_ref);\n nested_struct_aliases(x, 10);\n assert_eq(x, 3);\n nested_struct_aliases(x, 3);\n}\n\nfn add1(x: &mut Field) {\n *x += 1;\n}\n\nstruct S {\n y: Field,\n}\n\nstruct Nested {\n y: &mut &mut Field,\n}\n\nstruct C {\n foo: Field,\n bar: &mut C2,\n}\n\nstruct C2 {\n array: &mut [Field; 2],\n}\n\nimpl S {\n fn add2(&mut self) {\n self.y += 2;\n }\n\n fn get_y(self) -> Field {\n self.y\n }\n}\n\nfn mutate_copy(mut a: Field) {\n a = 7;\n}\n// Previously the `foo.bar` in `foo.bar.mutate()` would insert an automatic dereference\n// of `foo` which caused the method to wrongly be mutating a copy of bar rather than the original.\nfn regression_1887() {\n let foo = &mut Foo { bar: Bar { x: 0 } };\n foo.bar.mutate();\n assert(foo.bar.x == 32);\n}\n\nstruct Foo {\n bar: Bar,\n}\nstruct Bar {\n x: Field,\n}\n\nimpl Bar {\n fn mutate(&mut self) {\n self.x = 32;\n }\n}\n// Ensure that mutating a variable does not also mutate its copy\nfn regression_2054() {\n let mut x = 2;\n let z = x;\n\n x += 1;\n assert(z == 2);\n}\n// The compiler was still trying to convert an LValue from an array of structs to struct of arrays indexing,\n// even though this conversion was mostly removed elsewhere.\nfn regression_2030() {\n let ref = &mut 0;\n let mut array = [ref, ref];\n let _ = *array[0];\n *array[0] = 1;\n}\n\n// The `mut x: &mut ...` caught a bug handling lvalues where a double-dereference would occur internally\n// in one step rather than being tracked by two separate steps. This lead to assigning the 1 value to the\n// incorrect outer `mut` reference rather than the correct `&mut` reference.\nfn regression_2255() {\n let x = &mut 0;\n regression_2255_helper(x);\n assert(*x == 1);\n}\n\nfn regression_2255_helper(mut x: &mut Field) {\n *x = 1;\n}\n\n// Similar to `regression_2255` but without the double-dereferencing.\n// The test checks that `mem2reg` does not eliminate storing to a reference passed as a parameter.\nfn regression_6443() {\n let x = &mut 0;\n regression_6443_helper(x);\n assert(*x == 1);\n}\n\nfn regression_6443_helper(x: &mut Field) {\n *x = 1;\n}\n\nfn regression_2218(x: Field, y: Field) -> Field {\n let q = &mut &mut 0;\n let q1 = *q;\n let q2 = *q;\n\n if x != y {\n *q1 = 1;\n // Make sure that we correct load reference aliases through multiple blocks\n if x != 20 {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n } else {\n *q2 = 15;\n assert(*q1 == 15);\n }\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n // Have to assign value to return it\n let value = *q1;\n value\n}\n\nfn regression_2218_if_inner_if(x: Field, y: Field) {\n let value = regression_2218(x, y);\n assert(value == 2);\n}\n\nfn regression_2218_if_inner_else(x: Field, y: Field) {\n let value = regression_2218(x, y);\n assert(value == 15);\n}\n\nfn regression_2218_else(x: Field, y: Field) {\n let value = regression_2218(x, y);\n assert(value == 20);\n}\n\nfn regression_2218_loop(x: Field, y: Field) {\n let q = &mut &mut 0;\n let q1 = *q;\n let q2 = *q;\n\n for _ in 0..1 {\n if x != y {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n }\n assert(*q1 == 2);\n\n for _ in 0..1 {\n for _ in 0..5 {\n if x != y {\n *q1 = 1;\n // Make sure that we correct load reference aliases through multiple blocks\n if x != 20 {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n }\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n }\n if x != y {\n *q1 = 1;\n for _ in 0..5 {\n // Make sure that we correct load reference aliases through multiple blocks\n if x != 20 {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n }\n }\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n }\n assert(*q1 == 2);\n\n if x != y {\n for _ in 0..5 {\n if x != y {\n *q1 = 1;\n // Make sure that we correct load reference aliases through multiple blocks\n if x != 20 {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n }\n }\n }\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n assert(*q1 == 2);\n}\n// This is more a feature test than a proper regression.\n// Before, we never automatically dereferenced objects in method calls to their value types.\n// Now, we insert as many `*` as necessary to get to `S`.\nfn regression_2560(s_ref: &mut S) {\n assert(s_ref.get_y() == 7);\n}\n\nstruct MyStruct {\n a: Field,\n b: u32,\n}\n\nstruct Outer {\n inner: MyStruct,\n}\n\nfn nested_struct_aliases(x: Field, y: Field) {\n let mut var = Outer { inner: MyStruct { a: 0, b: 0 } };\n let ref_outer = &mut var;\n let ref_inner1 = &mut ref_outer.inner;\n let ref_inner2 = &mut var.inner;\n\n if x != y {\n (*ref_inner1).a = 5;\n (*ref_inner1).b = 7;\n (*ref_inner2).a = 3;\n (*ref_inner2).b = 10;\n\n for _ in 0..3 {\n (*ref_inner1).a += 1;\n (*ref_inner1).b += 2;\n (*ref_inner2).a += 2;\n (*ref_inner2).b += 4;\n }\n } else {\n (*ref_inner2).a = 20;\n (*ref_inner2).b = 15;\n (*ref_inner1).a = 25;\n (*ref_inner1).b = 30;\n\n for _ in 0..3 {\n (*ref_inner2).a += 5;\n (*ref_inner2).b += 3;\n (*ref_inner1).a += 4;\n (*ref_inner1).b += 10;\n }\n }\n\n if x != y {\n assert(var.inner.a == 12);\n assert(var.inner.b == 28);\n assert(ref_inner1.a == 12);\n assert(ref_inner1.b == 28);\n assert(ref_inner2.a == 12);\n assert(ref_inner2.b == 28);\n assert(ref_outer.inner.a == 12);\n assert(ref_outer.inner.b == 28);\n } else {\n assert(var.inner.a == 52);\n assert(var.inner.b == 69);\n assert(ref_inner1.a == 52);\n assert(ref_inner1.b == 69);\n assert(ref_inner2.a == 52);\n assert(ref_inner2.b == 69);\n assert(ref_outer.inner.a == 52);\n assert(ref_outer.inner.b == 69);\n }\n}\n", "path": "" } }, diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/references/execute__tests__force_brillig_false_inliner_9223372036854775807.snap b/tooling/nargo_cli/tests/snapshots/execution_success/references/execute__tests__force_brillig_false_inliner_9223372036854775807.snap index 4c239c5c2dc..ee05806bd41 100644 --- a/tooling/nargo_cli/tests/snapshots/execution_success/references/execute__tests__force_brillig_false_inliner_9223372036854775807.snap +++ b/tooling/nargo_cli/tests/snapshots/execution_success/references/execute__tests__force_brillig_false_inliner_9223372036854775807.snap @@ -26,10 +26,10 @@ expression: artifact "return value indices : []", "EXPR [ (1, _0) -2 ]" ], - "debug_symbols": "fZBNCoMwEIXvMmsXpipYr1KKxDhKICRhTApFvHtHiagLu5qfN98beDP02MWx1XZwEzSvGTrSxuixNU7JoJ3l7bxksI9tIERewUlnyktCG6Cx0ZgMPtLE7Wjy0m41SGI1zwBtz5UNB21w7ZbsoPN79FEntjzg6kqLe1qIUiSe2/rO4c//qkh89bzQb56k0nTJC3JoimU1Iy07gynDIVp1ijR8/a7soXtyCvtIuNptGj/4AQ==", + "debug_symbols": "fZBNCoMwEIXvMmsXGmtpvUopEuMogZCEMSkU8e4dJaIu7Gp+3nxv4E3QYRuHRtvejVC/JmhJG6OHxjglg3aWt9OcwTY2gRB5BQedKS8JbYDaRmMy+EgT16PRS7vWIInVPAO0HVc27LXBpZuznc6vUfFI7G2HqzNdXNOFEM/EF6K8Xzn8+V+Via+eJ/rNk1SaTnlBDnU5L2akZWswZdhHqw6Rhq/flC10T05hFwkXu1XjBz8=", "file_map": { "50": { - "source": "fn main(mut x: Field) {\n add1(&mut x);\n assert(x == 3);\n let mut s = S { y: x };\n s.add2();\n assert(s.y == 5);\n // Regression for #1946: Method resolution error when calling &mut methods with a variable of type &mut T\n let s_ref = &mut s;\n s_ref.add2();\n assert(s.y == 7);\n // Test that normal mutable variables are still copied\n let mut a = 0;\n mutate_copy(a);\n assert(a == 0);\n // Test something 3 allocations deep\n let mut nested_allocations = Nested { y: &mut &mut 0 };\n add1(*nested_allocations.y);\n assert(**nested_allocations.y == 1);\n // Test nested struct allocations with a mutable reference to an array.\n let mut c = C { foo: 0, bar: &mut C2 { array: &mut [1, 2] } };\n *c.bar.array = [3, 4];\n assert(*c.bar.array == [3, 4]);\n regression_1887();\n regression_2054();\n regression_2030();\n regression_2255();\n regression_6443();\n assert(x == 3);\n regression_2218_if_inner_if(x, 10);\n regression_2218_if_inner_else(20, x);\n regression_2218_else(x, 3);\n regression_2218_loop(x, 10);\n regression_2560(s_ref);\n}\n\nfn add1(x: &mut Field) {\n *x += 1;\n}\n\nstruct S {\n y: Field,\n}\n\nstruct Nested {\n y: &mut &mut Field,\n}\n\nstruct C {\n foo: Field,\n bar: &mut C2,\n}\n\nstruct C2 {\n array: &mut [Field; 2],\n}\n\nimpl S {\n fn add2(&mut self) {\n self.y += 2;\n }\n\n fn get_y(self) -> Field {\n self.y\n }\n}\n\nfn mutate_copy(mut a: Field) {\n a = 7;\n}\n// Previously the `foo.bar` in `foo.bar.mutate()` would insert an automatic dereference\n// of `foo` which caused the method to wrongly be mutating a copy of bar rather than the original.\nfn regression_1887() {\n let foo = &mut Foo { bar: Bar { x: 0 } };\n foo.bar.mutate();\n assert(foo.bar.x == 32);\n}\n\nstruct Foo {\n bar: Bar,\n}\nstruct Bar {\n x: Field,\n}\n\nimpl Bar {\n fn mutate(&mut self) {\n self.x = 32;\n }\n}\n// Ensure that mutating a variable does not also mutate its copy\nfn regression_2054() {\n let mut x = 2;\n let z = x;\n\n x += 1;\n assert(z == 2);\n}\n// The compiler was still trying to convert an LValue from an array of structs to struct of arrays indexing,\n// even though this conversion was mostly removed elsewhere.\nfn regression_2030() {\n let ref = &mut 0;\n let mut array = [ref, ref];\n let _ = *array[0];\n *array[0] = 1;\n}\n\n// The `mut x: &mut ...` caught a bug handling lvalues where a double-dereference would occur internally\n// in one step rather than being tracked by two separate steps. This lead to assigning the 1 value to the\n// incorrect outer `mut` reference rather than the correct `&mut` reference.\nfn regression_2255() {\n let x = &mut 0;\n regression_2255_helper(x);\n assert(*x == 1);\n}\n\nfn regression_2255_helper(mut x: &mut Field) {\n *x = 1;\n}\n\n// Similar to `regression_2255` but without the double-dereferencing.\n// The test checks that `mem2reg` does not eliminate storing to a reference passed as a parameter.\nfn regression_6443() {\n let x = &mut 0;\n regression_6443_helper(x);\n assert(*x == 1);\n}\n\nfn regression_6443_helper(x: &mut Field) {\n *x = 1;\n}\n\nfn regression_2218(x: Field, y: Field) -> Field {\n let q = &mut &mut 0;\n let q1 = *q;\n let q2 = *q;\n\n if x != y {\n *q1 = 1;\n // Make sure that we correct load reference aliases through multiple blocks\n if x != 20 {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n } else {\n *q2 = 15;\n assert(*q1 == 15);\n }\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n // Have to assign value to return it\n let value = *q1;\n value\n}\n\nfn regression_2218_if_inner_if(x: Field, y: Field) {\n let value = regression_2218(x, y);\n assert(value == 2);\n}\n\nfn regression_2218_if_inner_else(x: Field, y: Field) {\n let value = regression_2218(x, y);\n assert(value == 15);\n}\n\nfn regression_2218_else(x: Field, y: Field) {\n let value = regression_2218(x, y);\n assert(value == 20);\n}\n\nfn regression_2218_loop(x: Field, y: Field) {\n let q = &mut &mut 0;\n let q1 = *q;\n let q2 = *q;\n\n for _ in 0..1 {\n if x != y {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n }\n assert(*q1 == 2);\n\n for _ in 0..1 {\n for _ in 0..5 {\n if x != y {\n *q1 = 1;\n // Make sure that we correct load reference aliases through multiple blocks\n if x != 20 {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n }\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n }\n if x != y {\n *q1 = 1;\n for _ in 0..5 {\n // Make sure that we correct load reference aliases through multiple blocks\n if x != 20 {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n }\n }\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n }\n assert(*q1 == 2);\n\n if x != y {\n for _ in 0..5 {\n if x != y {\n *q1 = 1;\n // Make sure that we correct load reference aliases through multiple blocks\n if x != 20 {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n }\n }\n }\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n assert(*q1 == 2);\n}\n// This is more a feature test than a proper regression.\n// Before, we never automatically dereferenced objects in method calls to their value types.\n// Now, we insert as many `*` as necessary to get to `S`.\nfn regression_2560(s_ref: &mut S) {\n assert(s_ref.get_y() == 7);\n}\n", + "source": "fn main(mut x: Field) {\n add1(&mut x);\n assert(x == 3);\n let mut s = S { y: x };\n s.add2();\n assert(s.y == 5);\n // Regression for #1946: Method resolution error when calling &mut methods with a variable of type &mut T\n let s_ref = &mut s;\n s_ref.add2();\n assert(s.y == 7);\n // Test that normal mutable variables are still copied\n let mut a = 0;\n mutate_copy(a);\n assert(a == 0);\n // Test something 3 allocations deep\n let mut nested_allocations = Nested { y: &mut &mut 0 };\n add1(*nested_allocations.y);\n assert(**nested_allocations.y == 1);\n // Test nested struct allocations with a mutable reference to an array.\n let mut c = C { foo: 0, bar: &mut C2 { array: &mut [1, 2] } };\n *c.bar.array = [3, 4];\n assert(*c.bar.array == [3, 4]);\n regression_1887();\n regression_2054();\n regression_2030();\n regression_2255();\n regression_6443();\n assert(x == 3);\n regression_2218_if_inner_if(x, 10);\n regression_2218_if_inner_else(20, x);\n regression_2218_else(x, 3);\n regression_2218_loop(x, 10);\n regression_2560(s_ref);\n nested_struct_aliases(x, 10);\n assert_eq(x, 3);\n nested_struct_aliases(x, 3);\n}\n\nfn add1(x: &mut Field) {\n *x += 1;\n}\n\nstruct S {\n y: Field,\n}\n\nstruct Nested {\n y: &mut &mut Field,\n}\n\nstruct C {\n foo: Field,\n bar: &mut C2,\n}\n\nstruct C2 {\n array: &mut [Field; 2],\n}\n\nimpl S {\n fn add2(&mut self) {\n self.y += 2;\n }\n\n fn get_y(self) -> Field {\n self.y\n }\n}\n\nfn mutate_copy(mut a: Field) {\n a = 7;\n}\n// Previously the `foo.bar` in `foo.bar.mutate()` would insert an automatic dereference\n// of `foo` which caused the method to wrongly be mutating a copy of bar rather than the original.\nfn regression_1887() {\n let foo = &mut Foo { bar: Bar { x: 0 } };\n foo.bar.mutate();\n assert(foo.bar.x == 32);\n}\n\nstruct Foo {\n bar: Bar,\n}\nstruct Bar {\n x: Field,\n}\n\nimpl Bar {\n fn mutate(&mut self) {\n self.x = 32;\n }\n}\n// Ensure that mutating a variable does not also mutate its copy\nfn regression_2054() {\n let mut x = 2;\n let z = x;\n\n x += 1;\n assert(z == 2);\n}\n// The compiler was still trying to convert an LValue from an array of structs to struct of arrays indexing,\n// even though this conversion was mostly removed elsewhere.\nfn regression_2030() {\n let ref = &mut 0;\n let mut array = [ref, ref];\n let _ = *array[0];\n *array[0] = 1;\n}\n\n// The `mut x: &mut ...` caught a bug handling lvalues where a double-dereference would occur internally\n// in one step rather than being tracked by two separate steps. This lead to assigning the 1 value to the\n// incorrect outer `mut` reference rather than the correct `&mut` reference.\nfn regression_2255() {\n let x = &mut 0;\n regression_2255_helper(x);\n assert(*x == 1);\n}\n\nfn regression_2255_helper(mut x: &mut Field) {\n *x = 1;\n}\n\n// Similar to `regression_2255` but without the double-dereferencing.\n// The test checks that `mem2reg` does not eliminate storing to a reference passed as a parameter.\nfn regression_6443() {\n let x = &mut 0;\n regression_6443_helper(x);\n assert(*x == 1);\n}\n\nfn regression_6443_helper(x: &mut Field) {\n *x = 1;\n}\n\nfn regression_2218(x: Field, y: Field) -> Field {\n let q = &mut &mut 0;\n let q1 = *q;\n let q2 = *q;\n\n if x != y {\n *q1 = 1;\n // Make sure that we correct load reference aliases through multiple blocks\n if x != 20 {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n } else {\n *q2 = 15;\n assert(*q1 == 15);\n }\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n // Have to assign value to return it\n let value = *q1;\n value\n}\n\nfn regression_2218_if_inner_if(x: Field, y: Field) {\n let value = regression_2218(x, y);\n assert(value == 2);\n}\n\nfn regression_2218_if_inner_else(x: Field, y: Field) {\n let value = regression_2218(x, y);\n assert(value == 15);\n}\n\nfn regression_2218_else(x: Field, y: Field) {\n let value = regression_2218(x, y);\n assert(value == 20);\n}\n\nfn regression_2218_loop(x: Field, y: Field) {\n let q = &mut &mut 0;\n let q1 = *q;\n let q2 = *q;\n\n for _ in 0..1 {\n if x != y {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n }\n assert(*q1 == 2);\n\n for _ in 0..1 {\n for _ in 0..5 {\n if x != y {\n *q1 = 1;\n // Make sure that we correct load reference aliases through multiple blocks\n if x != 20 {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n }\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n }\n if x != y {\n *q1 = 1;\n for _ in 0..5 {\n // Make sure that we correct load reference aliases through multiple blocks\n if x != 20 {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n }\n }\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n }\n assert(*q1 == 2);\n\n if x != y {\n for _ in 0..5 {\n if x != y {\n *q1 = 1;\n // Make sure that we correct load reference aliases through multiple blocks\n if x != 20 {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n }\n }\n }\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n assert(*q1 == 2);\n}\n// This is more a feature test than a proper regression.\n// Before, we never automatically dereferenced objects in method calls to their value types.\n// Now, we insert as many `*` as necessary to get to `S`.\nfn regression_2560(s_ref: &mut S) {\n assert(s_ref.get_y() == 7);\n}\n\nstruct MyStruct {\n a: Field,\n b: u32,\n}\n\nstruct Outer {\n inner: MyStruct,\n}\n\nfn nested_struct_aliases(x: Field, y: Field) {\n let mut var = Outer { inner: MyStruct { a: 0, b: 0 } };\n let ref_outer = &mut var;\n let ref_inner1 = &mut ref_outer.inner;\n let ref_inner2 = &mut var.inner;\n\n if x != y {\n (*ref_inner1).a = 5;\n (*ref_inner1).b = 7;\n (*ref_inner2).a = 3;\n (*ref_inner2).b = 10;\n\n for _ in 0..3 {\n (*ref_inner1).a += 1;\n (*ref_inner1).b += 2;\n (*ref_inner2).a += 2;\n (*ref_inner2).b += 4;\n }\n } else {\n (*ref_inner2).a = 20;\n (*ref_inner2).b = 15;\n (*ref_inner1).a = 25;\n (*ref_inner1).b = 30;\n\n for _ in 0..3 {\n (*ref_inner2).a += 5;\n (*ref_inner2).b += 3;\n (*ref_inner1).a += 4;\n (*ref_inner1).b += 10;\n }\n }\n\n if x != y {\n assert(var.inner.a == 12);\n assert(var.inner.b == 28);\n assert(ref_inner1.a == 12);\n assert(ref_inner1.b == 28);\n assert(ref_inner2.a == 12);\n assert(ref_inner2.b == 28);\n assert(ref_outer.inner.a == 12);\n assert(ref_outer.inner.b == 28);\n } else {\n assert(var.inner.a == 52);\n assert(var.inner.b == 69);\n assert(ref_inner1.a == 52);\n assert(ref_inner1.b == 69);\n assert(ref_inner2.a == 52);\n assert(ref_inner2.b == 69);\n assert(ref_outer.inner.a == 52);\n assert(ref_outer.inner.b == 69);\n }\n}\n", "path": "" } }, diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/references/execute__tests__force_brillig_true_inliner_-9223372036854775808.snap b/tooling/nargo_cli/tests/snapshots/execution_success/references/execute__tests__force_brillig_true_inliner_-9223372036854775808.snap index 3f97c7d8db1..1f8fedc1029 100644 --- a/tooling/nargo_cli/tests/snapshots/execution_success/references/execute__tests__force_brillig_true_inliner_-9223372036854775808.snap +++ b/tooling/nargo_cli/tests/snapshots/execution_success/references/execute__tests__force_brillig_true_inliner_-9223372036854775808.snap @@ -35,16 +35,16 @@ expression: artifact "return value indices : []", "BRILLIG CALL func 0: inputs: [EXPR [ (1, _0) 0 ]], outputs: []", "unconstrained func 0", - "[Const { destination: Direct(2), bit_size: Integer(U32), value: 1 }, Const { destination: Direct(1), bit_size: Integer(U32), value: 32842 }, Const { destination: Direct(0), bit_size: Integer(U32), value: 3 }, Const { destination: Relative(2), bit_size: Integer(U32), value: 1 }, Const { destination: Relative(3), bit_size: Integer(U32), value: 0 }, CalldataCopy { destination_address: Direct(32841), size_address: Relative(2), offset_address: Relative(3) }, Mov { destination: Relative(1), source: Direct(32841) }, Call { location: 12 }, Call { location: 19 }, Const { destination: Relative(1), bit_size: Integer(U32), value: 32842 }, Const { destination: Relative(2), bit_size: Integer(U32), value: 0 }, Stop { return_data: HeapVector { pointer: Relative(1), size: Relative(2) } }, Const { destination: Direct(32835), bit_size: Field, value: 0 }, Const { destination: Direct(32836), bit_size: Integer(U32), value: 1 }, Const { destination: Direct(32837), bit_size: Field, value: 1 }, Const { destination: Direct(32838), bit_size: Field, value: 2 }, Const { destination: Direct(32839), bit_size: Field, value: 15 }, Const { destination: Direct(32840), bit_size: Field, value: 20 }, Return, Call { location: 106 }, BinaryFieldOp { destination: Relative(2), op: Add, lhs: Relative(1), rhs: Direct(32837) }, Const { destination: Relative(1), bit_size: Field, value: 3 }, BinaryFieldOp { destination: Relative(3), op: Equals, lhs: Relative(2), rhs: Relative(1) }, JumpIf { condition: Relative(3), location: 26 }, Const { destination: Relative(4), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(4) } }, Const { destination: Relative(2), bit_size: Field, value: 4 }, Mov { destination: Relative(3), source: Direct(1) }, Const { destination: Relative(4), bit_size: Integer(U32), value: 3 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(4) }, IndirectConst { destination_pointer: Relative(3), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(4), op: Add, bit_size: U32, lhs: Relative(3), rhs: Direct(2) }, Mov { destination: Relative(5), source: Relative(4) }, Store { destination_pointer: Relative(5), source: Relative(1) }, BinaryIntOp { destination: Relative(5), op: Add, bit_size: U32, lhs: Relative(5), rhs: Direct(2) }, Store { destination_pointer: Relative(5), source: Relative(2) }, Load { destination: Relative(2), source_pointer: Relative(3) }, Const { destination: Relative(4), bit_size: Integer(U32), value: 0 }, BinaryIntOp { destination: Relative(5), op: Equals, bit_size: U32, lhs: Relative(4), rhs: Relative(2) }, Not { destination: Relative(5), source: Relative(5), bit_size: U1 }, JumpIf { condition: Relative(5), location: 42 }, Call { location: 112 }, BinaryIntOp { destination: Relative(2), op: Add, bit_size: U32, lhs: Relative(2), rhs: Direct(2) }, Store { destination_pointer: Relative(3), source: Relative(2) }, Const { destination: Relative(5), bit_size: Integer(U32), value: 6 }, Mov { destination: Relative(6), source: Direct(0) }, Mov { destination: Relative(7), source: Relative(3) }, Mov { destination: Relative(8), source: Relative(3) }, BinaryIntOp { destination: Direct(0), op: Add, bit_size: U32, lhs: Direct(0), rhs: Relative(5) }, Call { location: 115 }, Mov { destination: Direct(0), source: Relative(0) }, Mov { destination: Relative(2), source: Relative(7) }, Const { destination: Relative(3), bit_size: Integer(U1), value: 1 }, JumpIf { condition: Relative(2), location: 56 }, Const { destination: Relative(5), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(5) } }, Const { destination: Relative(2), bit_size: Integer(U32), value: 5 }, Mov { destination: Relative(5), source: Direct(0) }, BinaryIntOp { destination: Direct(0), op: Add, bit_size: U32, lhs: Direct(0), rhs: Relative(2) }, Call { location: 129 }, Mov { destination: Direct(0), source: Relative(0) }, Const { destination: Relative(2), bit_size: Field, value: 10 }, Const { destination: Relative(5), bit_size: Integer(U32), value: 6 }, Mov { destination: Relative(6), source: Direct(0) }, Mov { destination: Relative(7), source: Relative(1) }, Mov { destination: Relative(8), source: Relative(2) }, BinaryIntOp { destination: Direct(0), op: Add, bit_size: U32, lhs: Direct(0), rhs: Relative(5) }, Call { location: 131 }, Mov { destination: Direct(0), source: Relative(0) }, Mov { destination: Relative(3), source: Relative(7) }, BinaryFieldOp { destination: Relative(5), op: Equals, lhs: Relative(3), rhs: Direct(32838) }, JumpIf { condition: Relative(5), location: 74 }, Const { destination: Relative(6), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(6) } }, Const { destination: Relative(5), bit_size: Integer(U32), value: 6 }, Mov { destination: Relative(6), source: Direct(0) }, Mov { destination: Relative(7), source: Direct(32840) }, Mov { destination: Relative(8), source: Relative(1) }, BinaryIntOp { destination: Direct(0), op: Add, bit_size: U32, lhs: Direct(0), rhs: Relative(5) }, Call { location: 131 }, Mov { destination: Direct(0), source: Relative(0) }, Mov { destination: Relative(3), source: Relative(7) }, BinaryFieldOp { destination: Relative(5), op: Equals, lhs: Relative(3), rhs: Direct(32839) }, JumpIf { condition: Relative(5), location: 86 }, Const { destination: Relative(6), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(6) } }, Const { destination: Relative(5), bit_size: Integer(U32), value: 6 }, Mov { destination: Relative(6), source: Direct(0) }, Mov { destination: Relative(7), source: Relative(1) }, Mov { destination: Relative(8), source: Relative(1) }, BinaryIntOp { destination: Direct(0), op: Add, bit_size: U32, lhs: Direct(0), rhs: Relative(5) }, Call { location: 131 }, Mov { destination: Direct(0), source: Relative(0) }, Mov { destination: Relative(3), source: Relative(7) }, BinaryFieldOp { destination: Relative(5), op: Equals, lhs: Relative(3), rhs: Direct(32840) }, JumpIf { condition: Relative(5), location: 98 }, Const { destination: Relative(6), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(6) } }, Const { destination: Relative(3), bit_size: Integer(U32), value: 5 }, Mov { destination: Relative(5), source: Direct(0) }, Mov { destination: Relative(6), source: Relative(1) }, Mov { destination: Relative(7), source: Relative(2) }, BinaryIntOp { destination: Direct(0), op: Add, bit_size: U32, lhs: Direct(0), rhs: Relative(3) }, Call { location: 150 }, Mov { destination: Direct(0), source: Relative(0) }, Return, Const { destination: Direct(32772), bit_size: Integer(U32), value: 30720 }, BinaryIntOp { destination: Direct(32771), op: LessThan, bit_size: U32, lhs: Direct(0), rhs: Direct(32772) }, JumpIf { condition: Direct(32771), location: 111 }, IndirectConst { destination_pointer: Direct(1), bit_size: Integer(U64), value: 17843811134343075018 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Direct(2) } }, Return, IndirectConst { destination_pointer: Direct(1), bit_size: Integer(U64), value: 12049594436772143978 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Direct(2) } }, Return, Call { location: 106 }, BinaryIntOp { destination: Relative(4), op: Add, bit_size: U32, lhs: Relative(1), rhs: Direct(32836) }, Load { destination: Relative(3), source_pointer: Relative(4) }, BinaryIntOp { destination: Relative(5), op: Add, bit_size: U32, lhs: Relative(2), rhs: Direct(32836) }, Load { destination: Relative(4), source_pointer: Relative(5) }, BinaryFieldOp { destination: Relative(5), op: Equals, lhs: Relative(3), rhs: Relative(4) }, Const { destination: Relative(3), bit_size: Integer(U32), value: 2 }, BinaryIntOp { destination: Relative(6), op: Add, bit_size: U32, lhs: Relative(1), rhs: Relative(3) }, Load { destination: Relative(4), source_pointer: Relative(6) }, BinaryIntOp { destination: Relative(6), op: Add, bit_size: U32, lhs: Relative(2), rhs: Relative(3) }, Load { destination: Relative(1), source_pointer: Relative(6) }, BinaryFieldOp { destination: Relative(2), op: Equals, lhs: Relative(4), rhs: Relative(1) }, BinaryIntOp { destination: Relative(1), op: Mul, bit_size: U1, lhs: Relative(5), rhs: Relative(2) }, Return, Call { location: 106 }, Return, Call { location: 106 }, Mov { destination: Relative(3), source: Direct(1) }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Direct(2) }, Store { destination_pointer: Relative(3), source: Direct(32835) }, BinaryFieldOp { destination: Relative(4), op: Equals, lhs: Relative(1), rhs: Relative(2) }, JumpIf { condition: Relative(4), location: 146 }, Jump { location: 138 }, Store { destination_pointer: Relative(3), source: Direct(32837) }, BinaryFieldOp { destination: Relative(2), op: Equals, lhs: Relative(1), rhs: Direct(32840) }, JumpIf { condition: Relative(2), location: 144 }, Jump { location: 142 }, Store { destination_pointer: Relative(3), source: Direct(32838) }, Jump { location: 148 }, Store { destination_pointer: Relative(3), source: Direct(32839) }, Jump { location: 148 }, Store { destination_pointer: Relative(3), source: Direct(32840) }, Jump { location: 148 }, Load { destination: Relative(1), source_pointer: Relative(3) }, Return, Call { location: 106 }, Mov { destination: Relative(3), source: Direct(1) }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Direct(2) }, Store { destination_pointer: Relative(3), source: Direct(32835) }, BinaryFieldOp { destination: Relative(4), op: Equals, lhs: Relative(1), rhs: Relative(2) }, JumpIf { condition: Relative(4), location: 159 }, Jump { location: 157 }, Store { destination_pointer: Relative(3), source: Direct(32838) }, Jump { location: 161 }, Store { destination_pointer: Relative(3), source: Direct(32840) }, Jump { location: 161 }, Load { destination: Relative(5), source_pointer: Relative(3) }, BinaryFieldOp { destination: Relative(6), op: Equals, lhs: Relative(5), rhs: Direct(32838) }, JumpIf { condition: Relative(6), location: 166 }, Const { destination: Relative(7), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(7) } }, BinaryFieldOp { destination: Relative(5), op: Equals, lhs: Relative(1), rhs: Direct(32840) }, Const { destination: Relative(1), bit_size: Integer(U32), value: 0 }, Const { destination: Relative(6), bit_size: Integer(U32), value: 5 }, Mov { destination: Relative(2), source: Relative(1) }, Jump { location: 171 }, BinaryIntOp { destination: Relative(7), op: LessThan, bit_size: U32, lhs: Relative(2), rhs: Relative(6) }, JumpIf { condition: Relative(7), location: 223 }, Jump { location: 174 }, JumpIf { condition: Relative(4), location: 190 }, Jump { location: 176 }, Store { destination_pointer: Relative(3), source: Direct(32837) }, Mov { destination: Relative(2), source: Relative(1) }, Jump { location: 179 }, BinaryIntOp { destination: Relative(7), op: LessThan, bit_size: U32, lhs: Relative(2), rhs: Relative(6) }, JumpIf { condition: Relative(7), location: 183 }, Jump { location: 182 }, Jump { location: 192 }, JumpIf { condition: Relative(5), location: 187 }, Jump { location: 185 }, Store { destination_pointer: Relative(3), source: Direct(32838) }, Jump { location: 187 }, BinaryIntOp { destination: Relative(7), op: Add, bit_size: U32, lhs: Relative(2), rhs: Direct(32836) }, Mov { destination: Relative(2), source: Relative(7) }, Jump { location: 179 }, Store { destination_pointer: Relative(3), source: Direct(32840) }, Jump { location: 192 }, Load { destination: Relative(2), source_pointer: Relative(3) }, BinaryFieldOp { destination: Relative(7), op: Equals, lhs: Relative(2), rhs: Direct(32838) }, JumpIf { condition: Relative(7), location: 197 }, Const { destination: Relative(8), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(8) } }, JumpIf { condition: Relative(4), location: 215 }, Jump { location: 199 }, Mov { destination: Relative(2), source: Relative(1) }, Jump { location: 201 }, BinaryIntOp { destination: Relative(1), op: LessThan, bit_size: U32, lhs: Relative(2), rhs: Relative(6) }, JumpIf { condition: Relative(1), location: 205 }, Jump { location: 204 }, Jump { location: 217 }, JumpIf { condition: Relative(4), location: 212 }, Jump { location: 207 }, Store { destination_pointer: Relative(3), source: Direct(32837) }, JumpIf { condition: Relative(5), location: 212 }, Jump { location: 210 }, Store { destination_pointer: Relative(3), source: Direct(32838) }, Jump { location: 212 }, BinaryIntOp { destination: Relative(1), op: Add, bit_size: U32, lhs: Relative(2), rhs: Direct(32836) }, Mov { destination: Relative(2), source: Relative(1) }, Jump { location: 201 }, Store { destination_pointer: Relative(3), source: Direct(32840) }, Jump { location: 217 }, Load { destination: Relative(1), source_pointer: Relative(3) }, BinaryFieldOp { destination: Relative(2), op: Equals, lhs: Relative(1), rhs: Direct(32838) }, JumpIf { condition: Relative(2), location: 222 }, Const { destination: Relative(3), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(3) } }, Return, JumpIf { condition: Relative(4), location: 230 }, Jump { location: 225 }, Store { destination_pointer: Relative(3), source: Direct(32837) }, JumpIf { condition: Relative(5), location: 232 }, Jump { location: 228 }, Store { destination_pointer: Relative(3), source: Direct(32838) }, Jump { location: 232 }, Store { destination_pointer: Relative(3), source: Direct(32840) }, Jump { location: 232 }, BinaryIntOp { destination: Relative(7), op: Add, bit_size: U32, lhs: Relative(2), rhs: Direct(32836) }, Mov { destination: Relative(2), source: Relative(7) }, Jump { location: 171 }]" + "[Const { destination: Direct(2), bit_size: Integer(U32), value: 1 }, Const { destination: Direct(1), bit_size: Integer(U32), value: 32843 }, Const { destination: Direct(0), bit_size: Integer(U32), value: 3 }, Const { destination: Relative(2), bit_size: Integer(U32), value: 1 }, Const { destination: Relative(3), bit_size: Integer(U32), value: 0 }, CalldataCopy { destination_address: Direct(32842), size_address: Relative(2), offset_address: Relative(3) }, Mov { destination: Relative(1), source: Direct(32842) }, Call { location: 12 }, Call { location: 20 }, Const { destination: Relative(1), bit_size: Integer(U32), value: 32843 }, Const { destination: Relative(2), bit_size: Integer(U32), value: 0 }, Stop { return_data: HeapVector { pointer: Relative(1), size: Relative(2) } }, Const { destination: Direct(32835), bit_size: Integer(U32), value: 0 }, Const { destination: Direct(32836), bit_size: Field, value: 0 }, Const { destination: Direct(32837), bit_size: Integer(U32), value: 1 }, Const { destination: Direct(32838), bit_size: Field, value: 1 }, Const { destination: Direct(32839), bit_size: Field, value: 2 }, Const { destination: Direct(32840), bit_size: Field, value: 15 }, Const { destination: Direct(32841), bit_size: Field, value: 20 }, Return, Call { location: 121 }, BinaryFieldOp { destination: Relative(2), op: Add, lhs: Relative(1), rhs: Direct(32838) }, Const { destination: Relative(1), bit_size: Field, value: 3 }, BinaryFieldOp { destination: Relative(3), op: Equals, lhs: Relative(2), rhs: Relative(1) }, JumpIf { condition: Relative(3), location: 27 }, Const { destination: Relative(4), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(4) } }, Const { destination: Relative(2), bit_size: Field, value: 4 }, Mov { destination: Relative(3), source: Direct(1) }, Const { destination: Relative(4), bit_size: Integer(U32), value: 3 }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Relative(4) }, IndirectConst { destination_pointer: Relative(3), bit_size: Integer(U32), value: 1 }, BinaryIntOp { destination: Relative(4), op: Add, bit_size: U32, lhs: Relative(3), rhs: Direct(2) }, Mov { destination: Relative(5), source: Relative(4) }, Store { destination_pointer: Relative(5), source: Relative(1) }, BinaryIntOp { destination: Relative(5), op: Add, bit_size: U32, lhs: Relative(5), rhs: Direct(2) }, Store { destination_pointer: Relative(5), source: Relative(2) }, Load { destination: Relative(2), source_pointer: Relative(3) }, Const { destination: Relative(4), bit_size: Integer(U32), value: 0 }, BinaryIntOp { destination: Relative(5), op: Equals, bit_size: U32, lhs: Relative(4), rhs: Relative(2) }, Not { destination: Relative(5), source: Relative(5), bit_size: U1 }, JumpIf { condition: Relative(5), location: 43 }, Call { location: 127 }, BinaryIntOp { destination: Relative(2), op: Add, bit_size: U32, lhs: Relative(2), rhs: Direct(2) }, Store { destination_pointer: Relative(3), source: Relative(2) }, Const { destination: Relative(5), bit_size: Integer(U32), value: 6 }, Mov { destination: Relative(6), source: Direct(0) }, Mov { destination: Relative(7), source: Relative(3) }, Mov { destination: Relative(8), source: Relative(3) }, BinaryIntOp { destination: Direct(0), op: Add, bit_size: U32, lhs: Direct(0), rhs: Relative(5) }, Call { location: 130 }, Mov { destination: Direct(0), source: Relative(0) }, Mov { destination: Relative(2), source: Relative(7) }, Const { destination: Relative(3), bit_size: Integer(U1), value: 1 }, JumpIf { condition: Relative(2), location: 57 }, Const { destination: Relative(5), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(5) } }, Const { destination: Relative(2), bit_size: Integer(U32), value: 5 }, Mov { destination: Relative(5), source: Direct(0) }, BinaryIntOp { destination: Direct(0), op: Add, bit_size: U32, lhs: Direct(0), rhs: Relative(2) }, Call { location: 144 }, Mov { destination: Direct(0), source: Relative(0) }, Const { destination: Relative(2), bit_size: Field, value: 10 }, Const { destination: Relative(5), bit_size: Integer(U32), value: 6 }, Mov { destination: Relative(6), source: Direct(0) }, Mov { destination: Relative(7), source: Relative(1) }, Mov { destination: Relative(8), source: Relative(2) }, BinaryIntOp { destination: Direct(0), op: Add, bit_size: U32, lhs: Direct(0), rhs: Relative(5) }, Call { location: 146 }, Mov { destination: Direct(0), source: Relative(0) }, Mov { destination: Relative(3), source: Relative(7) }, BinaryFieldOp { destination: Relative(5), op: Equals, lhs: Relative(3), rhs: Direct(32839) }, JumpIf { condition: Relative(5), location: 75 }, Const { destination: Relative(6), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(6) } }, Const { destination: Relative(5), bit_size: Integer(U32), value: 6 }, Mov { destination: Relative(6), source: Direct(0) }, Mov { destination: Relative(7), source: Direct(32841) }, Mov { destination: Relative(8), source: Relative(1) }, BinaryIntOp { destination: Direct(0), op: Add, bit_size: U32, lhs: Direct(0), rhs: Relative(5) }, Call { location: 146 }, Mov { destination: Direct(0), source: Relative(0) }, Mov { destination: Relative(3), source: Relative(7) }, BinaryFieldOp { destination: Relative(5), op: Equals, lhs: Relative(3), rhs: Direct(32840) }, JumpIf { condition: Relative(5), location: 87 }, Const { destination: Relative(6), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(6) } }, Const { destination: Relative(5), bit_size: Integer(U32), value: 6 }, Mov { destination: Relative(6), source: Direct(0) }, Mov { destination: Relative(7), source: Relative(1) }, Mov { destination: Relative(8), source: Relative(1) }, BinaryIntOp { destination: Direct(0), op: Add, bit_size: U32, lhs: Direct(0), rhs: Relative(5) }, Call { location: 146 }, Mov { destination: Direct(0), source: Relative(0) }, Mov { destination: Relative(3), source: Relative(7) }, BinaryFieldOp { destination: Relative(5), op: Equals, lhs: Relative(3), rhs: Direct(32841) }, JumpIf { condition: Relative(5), location: 99 }, Const { destination: Relative(6), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(6) } }, Const { destination: Relative(3), bit_size: Integer(U32), value: 5 }, Mov { destination: Relative(5), source: Direct(0) }, Mov { destination: Relative(6), source: Relative(1) }, Mov { destination: Relative(7), source: Relative(2) }, BinaryIntOp { destination: Direct(0), op: Add, bit_size: U32, lhs: Direct(0), rhs: Relative(3) }, Call { location: 165 }, Mov { destination: Direct(0), source: Relative(0) }, Const { destination: Relative(3), bit_size: Integer(U32), value: 5 }, Mov { destination: Relative(5), source: Direct(0) }, Mov { destination: Relative(6), source: Relative(1) }, Mov { destination: Relative(7), source: Relative(2) }, BinaryIntOp { destination: Direct(0), op: Add, bit_size: U32, lhs: Direct(0), rhs: Relative(3) }, Call { location: 249 }, Mov { destination: Direct(0), source: Relative(0) }, Const { destination: Relative(2), bit_size: Integer(U32), value: 5 }, Mov { destination: Relative(5), source: Direct(0) }, Mov { destination: Relative(6), source: Relative(1) }, Mov { destination: Relative(7), source: Relative(1) }, BinaryIntOp { destination: Direct(0), op: Add, bit_size: U32, lhs: Direct(0), rhs: Relative(2) }, Call { location: 249 }, Mov { destination: Direct(0), source: Relative(0) }, Return, Const { destination: Direct(32772), bit_size: Integer(U32), value: 30720 }, BinaryIntOp { destination: Direct(32771), op: LessThan, bit_size: U32, lhs: Direct(0), rhs: Direct(32772) }, JumpIf { condition: Direct(32771), location: 126 }, IndirectConst { destination_pointer: Direct(1), bit_size: Integer(U64), value: 17843811134343075018 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Direct(2) } }, Return, IndirectConst { destination_pointer: Direct(1), bit_size: Integer(U64), value: 12049594436772143978 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Direct(2) } }, Return, Call { location: 121 }, BinaryIntOp { destination: Relative(4), op: Add, bit_size: U32, lhs: Relative(1), rhs: Direct(32837) }, Load { destination: Relative(3), source_pointer: Relative(4) }, BinaryIntOp { destination: Relative(5), op: Add, bit_size: U32, lhs: Relative(2), rhs: Direct(32837) }, Load { destination: Relative(4), source_pointer: Relative(5) }, BinaryFieldOp { destination: Relative(5), op: Equals, lhs: Relative(3), rhs: Relative(4) }, Const { destination: Relative(3), bit_size: Integer(U32), value: 2 }, BinaryIntOp { destination: Relative(6), op: Add, bit_size: U32, lhs: Relative(1), rhs: Relative(3) }, Load { destination: Relative(4), source_pointer: Relative(6) }, BinaryIntOp { destination: Relative(6), op: Add, bit_size: U32, lhs: Relative(2), rhs: Relative(3) }, Load { destination: Relative(1), source_pointer: Relative(6) }, BinaryFieldOp { destination: Relative(2), op: Equals, lhs: Relative(4), rhs: Relative(1) }, BinaryIntOp { destination: Relative(1), op: Mul, bit_size: U1, lhs: Relative(5), rhs: Relative(2) }, Return, Call { location: 121 }, Return, Call { location: 121 }, Mov { destination: Relative(3), source: Direct(1) }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Direct(2) }, Store { destination_pointer: Relative(3), source: Direct(32836) }, BinaryFieldOp { destination: Relative(4), op: Equals, lhs: Relative(1), rhs: Relative(2) }, JumpIf { condition: Relative(4), location: 161 }, Jump { location: 153 }, Store { destination_pointer: Relative(3), source: Direct(32838) }, BinaryFieldOp { destination: Relative(2), op: Equals, lhs: Relative(1), rhs: Direct(32841) }, JumpIf { condition: Relative(2), location: 159 }, Jump { location: 157 }, Store { destination_pointer: Relative(3), source: Direct(32839) }, Jump { location: 163 }, Store { destination_pointer: Relative(3), source: Direct(32840) }, Jump { location: 163 }, Store { destination_pointer: Relative(3), source: Direct(32841) }, Jump { location: 163 }, Load { destination: Relative(1), source_pointer: Relative(3) }, Return, Call { location: 121 }, Mov { destination: Relative(3), source: Direct(1) }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Direct(2) }, Store { destination_pointer: Relative(3), source: Direct(32836) }, BinaryFieldOp { destination: Relative(4), op: Equals, lhs: Relative(1), rhs: Relative(2) }, JumpIf { condition: Relative(4), location: 174 }, Jump { location: 172 }, Store { destination_pointer: Relative(3), source: Direct(32839) }, Jump { location: 176 }, Store { destination_pointer: Relative(3), source: Direct(32841) }, Jump { location: 176 }, Load { destination: Relative(5), source_pointer: Relative(3) }, BinaryFieldOp { destination: Relative(6), op: Equals, lhs: Relative(5), rhs: Direct(32839) }, JumpIf { condition: Relative(6), location: 181 }, Const { destination: Relative(7), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(7) } }, BinaryFieldOp { destination: Relative(5), op: Equals, lhs: Relative(1), rhs: Direct(32841) }, Const { destination: Relative(1), bit_size: Integer(U32), value: 5 }, Mov { destination: Relative(2), source: Direct(32835) }, Jump { location: 185 }, BinaryIntOp { destination: Relative(6), op: LessThan, bit_size: U32, lhs: Relative(2), rhs: Relative(1) }, JumpIf { condition: Relative(6), location: 237 }, Jump { location: 188 }, JumpIf { condition: Relative(4), location: 204 }, Jump { location: 190 }, Store { destination_pointer: Relative(3), source: Direct(32838) }, Mov { destination: Relative(2), source: Direct(32835) }, Jump { location: 193 }, BinaryIntOp { destination: Relative(6), op: LessThan, bit_size: U32, lhs: Relative(2), rhs: Relative(1) }, JumpIf { condition: Relative(6), location: 197 }, Jump { location: 196 }, Jump { location: 206 }, JumpIf { condition: Relative(5), location: 201 }, Jump { location: 199 }, Store { destination_pointer: Relative(3), source: Direct(32839) }, Jump { location: 201 }, BinaryIntOp { destination: Relative(6), op: Add, bit_size: U32, lhs: Relative(2), rhs: Direct(32837) }, Mov { destination: Relative(2), source: Relative(6) }, Jump { location: 193 }, Store { destination_pointer: Relative(3), source: Direct(32841) }, Jump { location: 206 }, Load { destination: Relative(2), source_pointer: Relative(3) }, BinaryFieldOp { destination: Relative(6), op: Equals, lhs: Relative(2), rhs: Direct(32839) }, JumpIf { condition: Relative(6), location: 211 }, Const { destination: Relative(7), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(7) } }, JumpIf { condition: Relative(4), location: 229 }, Jump { location: 213 }, Mov { destination: Relative(2), source: Direct(32835) }, Jump { location: 215 }, BinaryIntOp { destination: Relative(6), op: LessThan, bit_size: U32, lhs: Relative(2), rhs: Relative(1) }, JumpIf { condition: Relative(6), location: 219 }, Jump { location: 218 }, Jump { location: 231 }, JumpIf { condition: Relative(4), location: 226 }, Jump { location: 221 }, Store { destination_pointer: Relative(3), source: Direct(32838) }, JumpIf { condition: Relative(5), location: 226 }, Jump { location: 224 }, Store { destination_pointer: Relative(3), source: Direct(32839) }, Jump { location: 226 }, BinaryIntOp { destination: Relative(6), op: Add, bit_size: U32, lhs: Relative(2), rhs: Direct(32837) }, Mov { destination: Relative(2), source: Relative(6) }, Jump { location: 215 }, Store { destination_pointer: Relative(3), source: Direct(32841) }, Jump { location: 231 }, Load { destination: Relative(1), source_pointer: Relative(3) }, BinaryFieldOp { destination: Relative(2), op: Equals, lhs: Relative(1), rhs: Direct(32839) }, JumpIf { condition: Relative(2), location: 236 }, Const { destination: Relative(3), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(3) } }, Return, JumpIf { condition: Relative(4), location: 244 }, Jump { location: 239 }, Store { destination_pointer: Relative(3), source: Direct(32838) }, JumpIf { condition: Relative(5), location: 246 }, Jump { location: 242 }, Store { destination_pointer: Relative(3), source: Direct(32839) }, Jump { location: 246 }, Store { destination_pointer: Relative(3), source: Direct(32841) }, Jump { location: 246 }, BinaryIntOp { destination: Relative(6), op: Add, bit_size: U32, lhs: Relative(2), rhs: Direct(32837) }, Mov { destination: Relative(2), source: Relative(6) }, Jump { location: 185 }, Call { location: 121 }, Mov { destination: Relative(3), source: Direct(1) }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Direct(2) }, Store { destination_pointer: Relative(3), source: Direct(32836) }, Mov { destination: Relative(4), source: Direct(1) }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Direct(2) }, Store { destination_pointer: Relative(4), source: Direct(32835) }, BinaryFieldOp { destination: Relative(5), op: Equals, lhs: Relative(1), rhs: Relative(2) }, Const { destination: Relative(1), bit_size: Field, value: 52 }, Const { destination: Relative(2), bit_size: Integer(U32), value: 69 }, Const { destination: Relative(6), bit_size: Field, value: 12 }, Const { destination: Relative(7), bit_size: Integer(U32), value: 28 }, JumpIf { condition: Relative(5), location: 266 }, Jump { location: 263 }, Store { destination_pointer: Relative(3), source: Relative(6) }, Store { destination_pointer: Relative(4), source: Relative(7) }, Jump { location: 269 }, Store { destination_pointer: Relative(3), source: Relative(1) }, Store { destination_pointer: Relative(4), source: Relative(2) }, Jump { location: 269 }, JumpIf { condition: Relative(5), location: 282 }, Jump { location: 271 }, Load { destination: Relative(1), source_pointer: Relative(3) }, BinaryFieldOp { destination: Relative(2), op: Equals, lhs: Relative(1), rhs: Relative(6) }, JumpIf { condition: Relative(2), location: 276 }, Const { destination: Relative(3), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(3) } }, Load { destination: Relative(1), source_pointer: Relative(4) }, BinaryIntOp { destination: Relative(2), op: Equals, bit_size: U32, lhs: Relative(1), rhs: Relative(7) }, JumpIf { condition: Relative(2), location: 281 }, Const { destination: Relative(3), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(3) } }, Jump { location: 293 }, Load { destination: Relative(5), source_pointer: Relative(3) }, BinaryFieldOp { destination: Relative(3), op: Equals, lhs: Relative(5), rhs: Relative(1) }, JumpIf { condition: Relative(3), location: 287 }, Const { destination: Relative(6), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(6) } }, Load { destination: Relative(1), source_pointer: Relative(4) }, BinaryIntOp { destination: Relative(3), op: Equals, bit_size: U32, lhs: Relative(1), rhs: Relative(2) }, JumpIf { condition: Relative(3), location: 292 }, Const { destination: Relative(4), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(4) } }, Jump { location: 293 }, Return]" ], - "debug_symbols": "nZjfaiM9DMXfZa57YVmW//RVllLSNl0CIS3Z5IOPkndfnZHtdBcSFt30d9IZnbFlWXHma3nbvpx/Pu8O7x+/lscfX8vLcbff734+7z9eN6fdx0H/+7UE/In6Nz4skZZHVkQDG5JBDHl5TIpiqIa2goOBDNHAhmQQg7qIohiqoa1IwUCGaGCDumSFGLKhGKqhrZBgIEM0sMFcxFxEXYqiGKqhrcjBoC5NEQ1sSAYxZEMxVENbUdSFgpI6Yyd3qhNp+ot05s7SWTubsYZO6oSfrk3lztQpnfDT7NXSWTubsYVO6oyd3Ak/zVSTztxZOuGnaWrNSCEMQUPEIXiI1AXBrUKUIeDXIFoXa30SBPV7UKMmeIg0bpYh8ohS56iJorUmcWmtylWkITRKAgSqEVFrPSJqrUGG0JslQaB+BQI3awoIhRZxD0rNBA+hURFRKLGIKFRXRBQKKyIJKK2IWaC4TKQhZAhMB0NFHTGGikJhDBWVwRgqlpzxUKw146FYXMZDsaqMh2JZGQ/FupqQIbKJiIXjCgGfhtaAzR0gkEOCwF5euwaaAXoDFi6hH2DhVoGFM0FDIEogcHNGm8E9eOi6OvVyeVhGh3o+HbdbNKhvLUsb2efmuD2clsfDeb9/WP7b7M/rTb8+N4eVp81Rr+pgt4c3pRq+7/ZbqMvDNTrcDkW+19h0DZY/o+l2NBHys8arrLcc7jwf1bbGS3NEF2k9vOTgiW9pxDfxxJdrfHbE1zTGX7MnvvFYvlbirfh6O55LkW7Ad2Zwz6GGMQWu5FnDVsYctImmm0VI98bQ8hhDo+KyaBymRSLHNLTxhzmPdDOVlG5bpDBzmQIHn0XiaSHJNQ98E/R5FM+Caksd04ghfsvEvxvMxVBZPQbfR9BuGMR7G7vmubGbZwDhOgB2GCS6NmaKnlVI1Mpw0DF4HGLK0yEVjwOnOQZOrllwCdPBVY0pXTdVItcschxNMmWOrjFkmmPILocWZyZbrC4HSdNBPF92QjzyoDK7HNqoaonB5RBLng7FdeCIbdSDcPAdWea3rnByzYJne1HpqUlJPB10Y3gcMk2HTD6HMjOZfbO4nt+kZHI5zNODFN8Yahg7Syp59kUSmrtbyLW7c5sOubkcapy9uvr6Q51H8VRdPYpjmIdJ3+7mKPMUFsXnUHg6FM/5h7mMtVDpySSnOB1SdGVS4jiDqXTNQuYvG5WuTGaamcx/zeJJP21ed8c/3q9d4HXcbV722/7x/Xx4/Xb19P/nuDLez30eP163b+fjFk7Xl3T4Bf6DQn4goie8HcFHff+jvzGfLnj8bw==", + "debug_symbols": "nVndTqM7DHyX75qLJHb+eJUVQgXKqlJVUBeOdIR49/XEccquVLTyDTOlnydOPHHS9mN72j+8/7w/nJ5ffm23Pz62h/PheDz8vD++PO7eDi8n+e/HFvAnxe023WwpbbckQAqskBWKQt1uWaAp9AEUFKJCUiAFVsgKRUFUskBT6AM4KESFpEAKrCAqRaAoVIWm0AfkoBAVkgIpsIKqZFXJolIFmkIfUIJCVBCVLkAKrJAVikJVaAp9QA0KohKDYJpIE3miKEVZ/lom1oltYldsYWKcmCZCT2rTeGKeWCZCT1avtYldsYeJcWKaSBN5IvRkpXqZWCe2idCTZYohGIlGkhEywkayEcg2kGqkGemTxGAkGklGoNxB2Eg2UoxUI81InwSmTQEkGRHBFEHYiAgmAin2TDXSjPT5MGysJM4oWDkxCAw73mpG+iTDtgkEVkXUMCuiYNCSQfCwrHeELQuWDo4sWAS4MOEZ+FBJM4LEEAX7JUTBdwlRMFzCIsBxhFnAckr6JDCdEhmUkCrsRUgV/iGkCsMQUoUTSAZNMAAVEDSRCoL+0UAwVgdpRvokqLISdIuAhoSWEkHQRkaLQgdBIxq9Bz1otB0MOhoPBh2tZxA2ko0gCvmgKIx80FoYg6KrZAyKWmQMiiaiJBkhI2wkG0E4MkRR8uiYbARvIVVUZxC0hIycUZSMxNAUlLCRbKQYQTiSR5mU9ElQJiUQxLzQFTLmhbagJBspRqoRGBJzR28YBMVVArOFz8+bzc6N+7fzfo9j48tBIsfL6+68P71tt6f34/Fm+293fB8P/XrdnQa+7c7yrkjuT0+CIvh8OO7BPm8u0eF6KDw7YvkSnP+MjtejY4LVR3xMVK4pfDM+ajnic3dE12zD1xI88Z0tvmdPfL3Ee2bf2PJvxRPfycrXa7oW367HUyu2/tQauxR6NYUeqmcO1eYgR9zVFOI3LqTeeLk4ZI8Eh3jZCMljRTmWw5oHXy1m5O+SWGvJcqq6JCKOkynByTUPNNw5j+paiRjNVHJ/iC6FsjwRXRtTDkvbWSmkL9X4dwEKS4CaR+BrBv2KQErfNJdWVnPpngTCJQFyCHCKloBQz9ZmOR6XQvc4gYnW1ibyOIGZVg5MrllwXr2Bi0/hsrFzcM2irj3FNXmOOs7rrOGcPQo5RFtJoa7DPnBaCkwehZTWhUHury6Fta1y6i4FKuZJob5LT6tLwXVxyJzWLJhcs+B1dxHq8WTOaSnk5FKoYSnU4FMoayWrbxaNl4Jcx1wKZdWiOXPoa2f1QK7d3dfuLsHVH2pdCrW5FHpcvbq7+gN3XreX7upRhar1B6GefVG4W7cv0qQ8CnVdqkttnmrWsFxdQ2sehbhqUaPrvJADpy2F7PpwFFctqnyv4VGgvhTY5ajKa3dXLuxSaGkpdE9/oLRmQb4Th2jVQu5DPoUSl0LxfC4gXp+1iV2nHuV1IaUcPX6QSdilXKhrFmVVU6hrJWtYK1n/msWdvNo9Hs5//BrwCa3zYfdw3M+Xz++nxy/vvv3/au/Yrwmv55fH/dP7eQ+ly08K+C7vR5QvQmMqd/jCdbys8rLffWL43w==", "file_map": { "5": { "source": "use crate::meta::derive_via;\n\n#[derive_via(derive_eq)]\n// docs:start:eq-trait\npub trait Eq {\n fn eq(self, other: Self) -> bool;\n}\n// docs:end:eq-trait\n\n// docs:start:derive_eq\ncomptime fn derive_eq(s: TypeDefinition) -> Quoted {\n let signature = quote { fn eq(_self: Self, _other: Self) -> bool };\n let for_each_field = |name| quote { (_self.$name == _other.$name) };\n let body = |fields| {\n if s.fields_as_written().len() == 0 {\n quote { true }\n } else {\n fields\n }\n };\n crate::meta::make_trait_impl(\n s,\n quote { $crate::cmp::Eq },\n signature,\n for_each_field,\n quote { & },\n body,\n )\n}\n// docs:end:derive_eq\n\nimpl Eq for Field {\n fn eq(self, other: Field) -> bool {\n self == other\n }\n}\n\nimpl Eq for u128 {\n fn eq(self, other: u128) -> bool {\n self == other\n }\n}\nimpl Eq for u64 {\n fn eq(self, other: u64) -> bool {\n self == other\n }\n}\nimpl Eq for u32 {\n fn eq(self, other: u32) -> bool {\n self == other\n }\n}\nimpl Eq for u16 {\n fn eq(self, other: u16) -> bool {\n self == other\n }\n}\nimpl Eq for u8 {\n fn eq(self, other: u8) -> bool {\n self == other\n }\n}\nimpl Eq for u1 {\n fn eq(self, other: u1) -> bool {\n self == other\n }\n}\n\nimpl Eq for i8 {\n fn eq(self, other: i8) -> bool {\n self == other\n }\n}\nimpl Eq for i16 {\n fn eq(self, other: i16) -> bool {\n self == other\n }\n}\nimpl Eq for i32 {\n fn eq(self, other: i32) -> bool {\n self == other\n }\n}\nimpl Eq for i64 {\n fn eq(self, other: i64) -> bool {\n self == other\n }\n}\n\nimpl Eq for () {\n fn eq(_self: Self, _other: ()) -> bool {\n true\n }\n}\nimpl Eq for bool {\n fn eq(self, other: bool) -> bool {\n self == other\n }\n}\n\nimpl Eq for [T; N]\nwhere\n T: Eq,\n{\n fn eq(self, other: [T; N]) -> bool {\n let mut result = true;\n for i in 0..self.len() {\n result &= self[i].eq(other[i]);\n }\n result\n }\n}\n\nimpl Eq for [T]\nwhere\n T: Eq,\n{\n fn eq(self, other: [T]) -> bool {\n let mut result = self.len() == other.len();\n if result {\n for i in 0..self.len() {\n result &= self[i].eq(other[i]);\n }\n }\n result\n }\n}\n\nimpl Eq for str {\n fn eq(self, other: str) -> bool {\n let self_bytes = self.as_bytes();\n let other_bytes = other.as_bytes();\n self_bytes == other_bytes\n }\n}\n\nimpl Eq for (A, B)\nwhere\n A: Eq,\n B: Eq,\n{\n fn eq(self, other: (A, B)) -> bool {\n self.0.eq(other.0) & self.1.eq(other.1)\n }\n}\n\nimpl Eq for (A, B, C)\nwhere\n A: Eq,\n B: Eq,\n C: Eq,\n{\n fn eq(self, other: (A, B, C)) -> bool {\n self.0.eq(other.0) & self.1.eq(other.1) & self.2.eq(other.2)\n }\n}\n\nimpl Eq for (A, B, C, D)\nwhere\n A: Eq,\n B: Eq,\n C: Eq,\n D: Eq,\n{\n fn eq(self, other: (A, B, C, D)) -> bool {\n self.0.eq(other.0) & self.1.eq(other.1) & self.2.eq(other.2) & self.3.eq(other.3)\n }\n}\n\nimpl Eq for (A, B, C, D, E)\nwhere\n A: Eq,\n B: Eq,\n C: Eq,\n D: Eq,\n E: Eq,\n{\n fn eq(self, other: (A, B, C, D, E)) -> bool {\n self.0.eq(other.0)\n & self.1.eq(other.1)\n & self.2.eq(other.2)\n & self.3.eq(other.3)\n & self.4.eq(other.4)\n }\n}\n\nimpl Eq for Ordering {\n fn eq(self, other: Ordering) -> bool {\n self.result == other.result\n }\n}\n\n// Noir doesn't have enums yet so we emulate (Lt | Eq | Gt) with a struct\n// that has 3 public functions for constructing the struct.\npub struct Ordering {\n result: Field,\n}\n\nimpl Ordering {\n // Implementation note: 0, 1, and 2 for Lt, Eq, and Gt are built\n // into the compiler, do not change these without also updating\n // the compiler itself!\n pub fn less() -> Ordering {\n Ordering { result: 0 }\n }\n\n pub fn equal() -> Ordering {\n Ordering { result: 1 }\n }\n\n pub fn greater() -> Ordering {\n Ordering { result: 2 }\n }\n}\n\n#[derive_via(derive_ord)]\n// docs:start:ord-trait\npub trait Ord {\n fn cmp(self, other: Self) -> Ordering;\n}\n// docs:end:ord-trait\n\n// docs:start:derive_ord\ncomptime fn derive_ord(s: TypeDefinition) -> Quoted {\n let name = quote { $crate::cmp::Ord };\n let signature = quote { fn cmp(_self: Self, _other: Self) -> $crate::cmp::Ordering };\n let for_each_field = |name| quote {\n if result == $crate::cmp::Ordering::equal() {\n result = _self.$name.cmp(_other.$name);\n }\n };\n let body = |fields| quote {\n let mut result = $crate::cmp::Ordering::equal();\n $fields\n result\n };\n crate::meta::make_trait_impl(s, name, signature, for_each_field, quote {}, body)\n}\n// docs:end:derive_ord\n\n// Note: Field deliberately does not implement Ord\n\nimpl Ord for u128 {\n fn cmp(self, other: u128) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\nimpl Ord for u64 {\n fn cmp(self, other: u64) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for u32 {\n fn cmp(self, other: u32) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for u16 {\n fn cmp(self, other: u16) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for u8 {\n fn cmp(self, other: u8) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i8 {\n fn cmp(self, other: i8) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i16 {\n fn cmp(self, other: i16) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i32 {\n fn cmp(self, other: i32) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for i64 {\n fn cmp(self, other: i64) -> Ordering {\n if self < other {\n Ordering::less()\n } else if self > other {\n Ordering::greater()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for () {\n fn cmp(_self: Self, _other: ()) -> Ordering {\n Ordering::equal()\n }\n}\n\nimpl Ord for bool {\n fn cmp(self, other: bool) -> Ordering {\n if self {\n if other {\n Ordering::equal()\n } else {\n Ordering::greater()\n }\n } else if other {\n Ordering::less()\n } else {\n Ordering::equal()\n }\n }\n}\n\nimpl Ord for [T; N]\nwhere\n T: Ord,\n{\n // The first non-equal element of both arrays determines\n // the ordering for the whole array.\n fn cmp(self, other: [T; N]) -> Ordering {\n let mut result = Ordering::equal();\n for i in 0..self.len() {\n if result == Ordering::equal() {\n result = self[i].cmp(other[i]);\n }\n }\n result\n }\n}\n\nimpl Ord for [T]\nwhere\n T: Ord,\n{\n // The first non-equal element of both arrays determines\n // the ordering for the whole array.\n fn cmp(self, other: [T]) -> Ordering {\n let mut result = self.len().cmp(other.len());\n for i in 0..self.len() {\n if result == Ordering::equal() {\n result = self[i].cmp(other[i]);\n }\n }\n result\n }\n}\n\nimpl Ord for (A, B)\nwhere\n A: Ord,\n B: Ord,\n{\n fn cmp(self, other: (A, B)) -> Ordering {\n let result = self.0.cmp(other.0);\n\n if result != Ordering::equal() {\n result\n } else {\n self.1.cmp(other.1)\n }\n }\n}\n\nimpl Ord for (A, B, C)\nwhere\n A: Ord,\n B: Ord,\n C: Ord,\n{\n fn cmp(self, other: (A, B, C)) -> Ordering {\n let mut result = self.0.cmp(other.0);\n\n if result == Ordering::equal() {\n result = self.1.cmp(other.1);\n }\n\n if result == Ordering::equal() {\n result = self.2.cmp(other.2);\n }\n\n result\n }\n}\n\nimpl Ord for (A, B, C, D)\nwhere\n A: Ord,\n B: Ord,\n C: Ord,\n D: Ord,\n{\n fn cmp(self, other: (A, B, C, D)) -> Ordering {\n let mut result = self.0.cmp(other.0);\n\n if result == Ordering::equal() {\n result = self.1.cmp(other.1);\n }\n\n if result == Ordering::equal() {\n result = self.2.cmp(other.2);\n }\n\n if result == Ordering::equal() {\n result = self.3.cmp(other.3);\n }\n\n result\n }\n}\n\nimpl Ord for (A, B, C, D, E)\nwhere\n A: Ord,\n B: Ord,\n C: Ord,\n D: Ord,\n E: Ord,\n{\n fn cmp(self, other: (A, B, C, D, E)) -> Ordering {\n let mut result = self.0.cmp(other.0);\n\n if result == Ordering::equal() {\n result = self.1.cmp(other.1);\n }\n\n if result == Ordering::equal() {\n result = self.2.cmp(other.2);\n }\n\n if result == Ordering::equal() {\n result = self.3.cmp(other.3);\n }\n\n if result == Ordering::equal() {\n result = self.4.cmp(other.4);\n }\n\n result\n }\n}\n\n// Compares and returns the maximum of two values.\n//\n// Returns the second argument if the comparison determines them to be equal.\n//\n// # Examples\n//\n// ```\n// use std::cmp;\n//\n// assert_eq(cmp::max(1, 2), 2);\n// assert_eq(cmp::max(2, 2), 2);\n// ```\npub fn max(v1: T, v2: T) -> T\nwhere\n T: Ord,\n{\n if v1 > v2 {\n v1\n } else {\n v2\n }\n}\n\n// Compares and returns the minimum of two values.\n//\n// Returns the first argument if the comparison determines them to be equal.\n//\n// # Examples\n//\n// ```\n// use std::cmp;\n//\n// assert_eq(cmp::min(1, 2), 1);\n// assert_eq(cmp::min(2, 2), 2);\n// ```\npub fn min(v1: T, v2: T) -> T\nwhere\n T: Ord,\n{\n if v1 > v2 {\n v2\n } else {\n v1\n }\n}\n\nmod cmp_tests {\n use super::{Eq, max, min};\n\n #[test]\n fn sanity_check_min() {\n assert_eq(min(0_u64, 1), 0);\n assert_eq(min(0_u64, 0), 0);\n assert_eq(min(1_u64, 1), 1);\n assert_eq(min(255_u8, 0), 0);\n }\n\n #[test]\n fn sanity_check_max() {\n assert_eq(max(0_u64, 1), 1);\n assert_eq(max(0_u64, 0), 0);\n assert_eq(max(1_u64, 1), 1);\n assert_eq(max(255_u8, 0), 255);\n }\n\n #[test]\n fn correctly_handles_unequal_length_slices() {\n let slice_1 = &[0, 1, 2, 3];\n let slice_2 = &[0, 1, 2];\n assert(!slice_1.eq(slice_2));\n }\n}\n", "path": "std/cmp.nr" }, "50": { - "source": "fn main(mut x: Field) {\n add1(&mut x);\n assert(x == 3);\n let mut s = S { y: x };\n s.add2();\n assert(s.y == 5);\n // Regression for #1946: Method resolution error when calling &mut methods with a variable of type &mut T\n let s_ref = &mut s;\n s_ref.add2();\n assert(s.y == 7);\n // Test that normal mutable variables are still copied\n let mut a = 0;\n mutate_copy(a);\n assert(a == 0);\n // Test something 3 allocations deep\n let mut nested_allocations = Nested { y: &mut &mut 0 };\n add1(*nested_allocations.y);\n assert(**nested_allocations.y == 1);\n // Test nested struct allocations with a mutable reference to an array.\n let mut c = C { foo: 0, bar: &mut C2 { array: &mut [1, 2] } };\n *c.bar.array = [3, 4];\n assert(*c.bar.array == [3, 4]);\n regression_1887();\n regression_2054();\n regression_2030();\n regression_2255();\n regression_6443();\n assert(x == 3);\n regression_2218_if_inner_if(x, 10);\n regression_2218_if_inner_else(20, x);\n regression_2218_else(x, 3);\n regression_2218_loop(x, 10);\n regression_2560(s_ref);\n}\n\nfn add1(x: &mut Field) {\n *x += 1;\n}\n\nstruct S {\n y: Field,\n}\n\nstruct Nested {\n y: &mut &mut Field,\n}\n\nstruct C {\n foo: Field,\n bar: &mut C2,\n}\n\nstruct C2 {\n array: &mut [Field; 2],\n}\n\nimpl S {\n fn add2(&mut self) {\n self.y += 2;\n }\n\n fn get_y(self) -> Field {\n self.y\n }\n}\n\nfn mutate_copy(mut a: Field) {\n a = 7;\n}\n// Previously the `foo.bar` in `foo.bar.mutate()` would insert an automatic dereference\n// of `foo` which caused the method to wrongly be mutating a copy of bar rather than the original.\nfn regression_1887() {\n let foo = &mut Foo { bar: Bar { x: 0 } };\n foo.bar.mutate();\n assert(foo.bar.x == 32);\n}\n\nstruct Foo {\n bar: Bar,\n}\nstruct Bar {\n x: Field,\n}\n\nimpl Bar {\n fn mutate(&mut self) {\n self.x = 32;\n }\n}\n// Ensure that mutating a variable does not also mutate its copy\nfn regression_2054() {\n let mut x = 2;\n let z = x;\n\n x += 1;\n assert(z == 2);\n}\n// The compiler was still trying to convert an LValue from an array of structs to struct of arrays indexing,\n// even though this conversion was mostly removed elsewhere.\nfn regression_2030() {\n let ref = &mut 0;\n let mut array = [ref, ref];\n let _ = *array[0];\n *array[0] = 1;\n}\n\n// The `mut x: &mut ...` caught a bug handling lvalues where a double-dereference would occur internally\n// in one step rather than being tracked by two separate steps. This lead to assigning the 1 value to the\n// incorrect outer `mut` reference rather than the correct `&mut` reference.\nfn regression_2255() {\n let x = &mut 0;\n regression_2255_helper(x);\n assert(*x == 1);\n}\n\nfn regression_2255_helper(mut x: &mut Field) {\n *x = 1;\n}\n\n// Similar to `regression_2255` but without the double-dereferencing.\n// The test checks that `mem2reg` does not eliminate storing to a reference passed as a parameter.\nfn regression_6443() {\n let x = &mut 0;\n regression_6443_helper(x);\n assert(*x == 1);\n}\n\nfn regression_6443_helper(x: &mut Field) {\n *x = 1;\n}\n\nfn regression_2218(x: Field, y: Field) -> Field {\n let q = &mut &mut 0;\n let q1 = *q;\n let q2 = *q;\n\n if x != y {\n *q1 = 1;\n // Make sure that we correct load reference aliases through multiple blocks\n if x != 20 {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n } else {\n *q2 = 15;\n assert(*q1 == 15);\n }\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n // Have to assign value to return it\n let value = *q1;\n value\n}\n\nfn regression_2218_if_inner_if(x: Field, y: Field) {\n let value = regression_2218(x, y);\n assert(value == 2);\n}\n\nfn regression_2218_if_inner_else(x: Field, y: Field) {\n let value = regression_2218(x, y);\n assert(value == 15);\n}\n\nfn regression_2218_else(x: Field, y: Field) {\n let value = regression_2218(x, y);\n assert(value == 20);\n}\n\nfn regression_2218_loop(x: Field, y: Field) {\n let q = &mut &mut 0;\n let q1 = *q;\n let q2 = *q;\n\n for _ in 0..1 {\n if x != y {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n }\n assert(*q1 == 2);\n\n for _ in 0..1 {\n for _ in 0..5 {\n if x != y {\n *q1 = 1;\n // Make sure that we correct load reference aliases through multiple blocks\n if x != 20 {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n }\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n }\n if x != y {\n *q1 = 1;\n for _ in 0..5 {\n // Make sure that we correct load reference aliases through multiple blocks\n if x != 20 {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n }\n }\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n }\n assert(*q1 == 2);\n\n if x != y {\n for _ in 0..5 {\n if x != y {\n *q1 = 1;\n // Make sure that we correct load reference aliases through multiple blocks\n if x != 20 {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n }\n }\n }\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n assert(*q1 == 2);\n}\n// This is more a feature test than a proper regression.\n// Before, we never automatically dereferenced objects in method calls to their value types.\n// Now, we insert as many `*` as necessary to get to `S`.\nfn regression_2560(s_ref: &mut S) {\n assert(s_ref.get_y() == 7);\n}\n", + "source": "fn main(mut x: Field) {\n add1(&mut x);\n assert(x == 3);\n let mut s = S { y: x };\n s.add2();\n assert(s.y == 5);\n // Regression for #1946: Method resolution error when calling &mut methods with a variable of type &mut T\n let s_ref = &mut s;\n s_ref.add2();\n assert(s.y == 7);\n // Test that normal mutable variables are still copied\n let mut a = 0;\n mutate_copy(a);\n assert(a == 0);\n // Test something 3 allocations deep\n let mut nested_allocations = Nested { y: &mut &mut 0 };\n add1(*nested_allocations.y);\n assert(**nested_allocations.y == 1);\n // Test nested struct allocations with a mutable reference to an array.\n let mut c = C { foo: 0, bar: &mut C2 { array: &mut [1, 2] } };\n *c.bar.array = [3, 4];\n assert(*c.bar.array == [3, 4]);\n regression_1887();\n regression_2054();\n regression_2030();\n regression_2255();\n regression_6443();\n assert(x == 3);\n regression_2218_if_inner_if(x, 10);\n regression_2218_if_inner_else(20, x);\n regression_2218_else(x, 3);\n regression_2218_loop(x, 10);\n regression_2560(s_ref);\n nested_struct_aliases(x, 10);\n assert_eq(x, 3);\n nested_struct_aliases(x, 3);\n}\n\nfn add1(x: &mut Field) {\n *x += 1;\n}\n\nstruct S {\n y: Field,\n}\n\nstruct Nested {\n y: &mut &mut Field,\n}\n\nstruct C {\n foo: Field,\n bar: &mut C2,\n}\n\nstruct C2 {\n array: &mut [Field; 2],\n}\n\nimpl S {\n fn add2(&mut self) {\n self.y += 2;\n }\n\n fn get_y(self) -> Field {\n self.y\n }\n}\n\nfn mutate_copy(mut a: Field) {\n a = 7;\n}\n// Previously the `foo.bar` in `foo.bar.mutate()` would insert an automatic dereference\n// of `foo` which caused the method to wrongly be mutating a copy of bar rather than the original.\nfn regression_1887() {\n let foo = &mut Foo { bar: Bar { x: 0 } };\n foo.bar.mutate();\n assert(foo.bar.x == 32);\n}\n\nstruct Foo {\n bar: Bar,\n}\nstruct Bar {\n x: Field,\n}\n\nimpl Bar {\n fn mutate(&mut self) {\n self.x = 32;\n }\n}\n// Ensure that mutating a variable does not also mutate its copy\nfn regression_2054() {\n let mut x = 2;\n let z = x;\n\n x += 1;\n assert(z == 2);\n}\n// The compiler was still trying to convert an LValue from an array of structs to struct of arrays indexing,\n// even though this conversion was mostly removed elsewhere.\nfn regression_2030() {\n let ref = &mut 0;\n let mut array = [ref, ref];\n let _ = *array[0];\n *array[0] = 1;\n}\n\n// The `mut x: &mut ...` caught a bug handling lvalues where a double-dereference would occur internally\n// in one step rather than being tracked by two separate steps. This lead to assigning the 1 value to the\n// incorrect outer `mut` reference rather than the correct `&mut` reference.\nfn regression_2255() {\n let x = &mut 0;\n regression_2255_helper(x);\n assert(*x == 1);\n}\n\nfn regression_2255_helper(mut x: &mut Field) {\n *x = 1;\n}\n\n// Similar to `regression_2255` but without the double-dereferencing.\n// The test checks that `mem2reg` does not eliminate storing to a reference passed as a parameter.\nfn regression_6443() {\n let x = &mut 0;\n regression_6443_helper(x);\n assert(*x == 1);\n}\n\nfn regression_6443_helper(x: &mut Field) {\n *x = 1;\n}\n\nfn regression_2218(x: Field, y: Field) -> Field {\n let q = &mut &mut 0;\n let q1 = *q;\n let q2 = *q;\n\n if x != y {\n *q1 = 1;\n // Make sure that we correct load reference aliases through multiple blocks\n if x != 20 {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n } else {\n *q2 = 15;\n assert(*q1 == 15);\n }\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n // Have to assign value to return it\n let value = *q1;\n value\n}\n\nfn regression_2218_if_inner_if(x: Field, y: Field) {\n let value = regression_2218(x, y);\n assert(value == 2);\n}\n\nfn regression_2218_if_inner_else(x: Field, y: Field) {\n let value = regression_2218(x, y);\n assert(value == 15);\n}\n\nfn regression_2218_else(x: Field, y: Field) {\n let value = regression_2218(x, y);\n assert(value == 20);\n}\n\nfn regression_2218_loop(x: Field, y: Field) {\n let q = &mut &mut 0;\n let q1 = *q;\n let q2 = *q;\n\n for _ in 0..1 {\n if x != y {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n }\n assert(*q1 == 2);\n\n for _ in 0..1 {\n for _ in 0..5 {\n if x != y {\n *q1 = 1;\n // Make sure that we correct load reference aliases through multiple blocks\n if x != 20 {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n }\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n }\n if x != y {\n *q1 = 1;\n for _ in 0..5 {\n // Make sure that we correct load reference aliases through multiple blocks\n if x != 20 {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n }\n }\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n }\n assert(*q1 == 2);\n\n if x != y {\n for _ in 0..5 {\n if x != y {\n *q1 = 1;\n // Make sure that we correct load reference aliases through multiple blocks\n if x != 20 {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n }\n }\n }\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n assert(*q1 == 2);\n}\n// This is more a feature test than a proper regression.\n// Before, we never automatically dereferenced objects in method calls to their value types.\n// Now, we insert as many `*` as necessary to get to `S`.\nfn regression_2560(s_ref: &mut S) {\n assert(s_ref.get_y() == 7);\n}\n\nstruct MyStruct {\n a: Field,\n b: u32,\n}\n\nstruct Outer {\n inner: MyStruct,\n}\n\nfn nested_struct_aliases(x: Field, y: Field) {\n let mut var = Outer { inner: MyStruct { a: 0, b: 0 } };\n let ref_outer = &mut var;\n let ref_inner1 = &mut ref_outer.inner;\n let ref_inner2 = &mut var.inner;\n\n if x != y {\n (*ref_inner1).a = 5;\n (*ref_inner1).b = 7;\n (*ref_inner2).a = 3;\n (*ref_inner2).b = 10;\n\n for _ in 0..3 {\n (*ref_inner1).a += 1;\n (*ref_inner1).b += 2;\n (*ref_inner2).a += 2;\n (*ref_inner2).b += 4;\n }\n } else {\n (*ref_inner2).a = 20;\n (*ref_inner2).b = 15;\n (*ref_inner1).a = 25;\n (*ref_inner1).b = 30;\n\n for _ in 0..3 {\n (*ref_inner2).a += 5;\n (*ref_inner2).b += 3;\n (*ref_inner1).a += 4;\n (*ref_inner1).b += 10;\n }\n }\n\n if x != y {\n assert(var.inner.a == 12);\n assert(var.inner.b == 28);\n assert(ref_inner1.a == 12);\n assert(ref_inner1.b == 28);\n assert(ref_inner2.a == 12);\n assert(ref_inner2.b == 28);\n assert(ref_outer.inner.a == 12);\n assert(ref_outer.inner.b == 28);\n } else {\n assert(var.inner.a == 52);\n assert(var.inner.b == 69);\n assert(ref_inner1.a == 52);\n assert(ref_inner1.b == 69);\n assert(ref_inner2.a == 52);\n assert(ref_inner2.b == 69);\n assert(ref_outer.inner.a == 52);\n assert(ref_outer.inner.b == 69);\n }\n}\n", "path": "" } }, diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/references/execute__tests__force_brillig_true_inliner_0.snap b/tooling/nargo_cli/tests/snapshots/execution_success/references/execute__tests__force_brillig_true_inliner_0.snap index 292fe479ef6..7064630fc84 100644 --- a/tooling/nargo_cli/tests/snapshots/execution_success/references/execute__tests__force_brillig_true_inliner_0.snap +++ b/tooling/nargo_cli/tests/snapshots/execution_success/references/execute__tests__force_brillig_true_inliner_0.snap @@ -31,12 +31,12 @@ expression: artifact "return value indices : []", "BRILLIG CALL func 0: inputs: [EXPR [ (1, _0) 0 ]], outputs: []", "unconstrained func 0", - "[Const { destination: Direct(2), bit_size: Integer(U32), value: 1 }, Const { destination: Direct(1), bit_size: Integer(U32), value: 32840 }, Const { destination: Direct(0), bit_size: Integer(U32), value: 3 }, Const { destination: Relative(2), bit_size: Integer(U32), value: 1 }, Const { destination: Relative(3), bit_size: Integer(U32), value: 0 }, CalldataCopy { destination_address: Direct(32839), size_address: Relative(2), offset_address: Relative(3) }, Mov { destination: Relative(1), source: Direct(32839) }, Call { location: 12 }, Call { location: 17 }, Const { destination: Relative(1), bit_size: Integer(U32), value: 32840 }, Const { destination: Relative(2), bit_size: Integer(U32), value: 0 }, Stop { return_data: HeapVector { pointer: Relative(1), size: Relative(2) } }, Const { destination: Direct(32835), bit_size: Field, value: 1 }, Const { destination: Direct(32836), bit_size: Field, value: 2 }, Const { destination: Direct(32837), bit_size: Field, value: 15 }, Const { destination: Direct(32838), bit_size: Field, value: 20 }, Return, Call { location: 120 }, BinaryFieldOp { destination: Relative(3), op: Add, lhs: Relative(1), rhs: Direct(32835) }, Const { destination: Relative(1), bit_size: Field, value: 3 }, BinaryFieldOp { destination: Relative(4), op: Equals, lhs: Relative(3), rhs: Relative(1) }, JumpIf { condition: Relative(4), location: 24 }, Const { destination: Relative(5), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(5) } }, Mov { destination: Relative(3), source: Direct(1) }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Direct(2) }, Const { destination: Relative(4), bit_size: Field, value: 7 }, Store { destination_pointer: Relative(3), source: Relative(4) }, Const { destination: Relative(5), bit_size: Integer(U32), value: 6 }, Mov { destination: Relative(6), source: Direct(0) }, BinaryIntOp { destination: Direct(0), op: Add, bit_size: U32, lhs: Direct(0), rhs: Relative(5) }, Call { location: 126 }, Mov { destination: Direct(0), source: Relative(0) }, Const { destination: Relative(5), bit_size: Field, value: 10 }, Const { destination: Relative(7), bit_size: Integer(U32), value: 8 }, Mov { destination: Relative(8), source: Direct(0) }, Mov { destination: Relative(9), source: Relative(1) }, Mov { destination: Relative(10), source: Relative(5) }, BinaryIntOp { destination: Direct(0), op: Add, bit_size: U32, lhs: Direct(0), rhs: Relative(7) }, Call { location: 128 }, Mov { destination: Direct(0), source: Relative(0) }, Mov { destination: Relative(6), source: Relative(9) }, BinaryFieldOp { destination: Relative(5), op: Equals, lhs: Relative(6), rhs: Direct(32836) }, JumpIf { condition: Relative(5), location: 46 }, Const { destination: Relative(7), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(7) } }, Const { destination: Relative(6), bit_size: Integer(U32), value: 7 }, Mov { destination: Relative(7), source: Direct(0) }, Mov { destination: Relative(8), source: Direct(32838) }, Mov { destination: Relative(9), source: Relative(1) }, BinaryIntOp { destination: Direct(0), op: Add, bit_size: U32, lhs: Direct(0), rhs: Relative(6) }, Call { location: 128 }, Mov { destination: Direct(0), source: Relative(0) }, Mov { destination: Relative(5), source: Relative(8) }, BinaryFieldOp { destination: Relative(6), op: Equals, lhs: Relative(5), rhs: Direct(32837) }, JumpIf { condition: Relative(6), location: 58 }, Const { destination: Relative(7), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(7) } }, Const { destination: Relative(6), bit_size: Integer(U32), value: 7 }, Mov { destination: Relative(7), source: Direct(0) }, Mov { destination: Relative(8), source: Relative(1) }, Mov { destination: Relative(9), source: Relative(1) }, BinaryIntOp { destination: Direct(0), op: Add, bit_size: U32, lhs: Direct(0), rhs: Relative(6) }, Call { location: 128 }, Mov { destination: Direct(0), source: Relative(0) }, Mov { destination: Relative(5), source: Relative(8) }, BinaryFieldOp { destination: Relative(1), op: Equals, lhs: Relative(5), rhs: Direct(32838) }, JumpIf { condition: Relative(1), location: 70 }, Const { destination: Relative(6), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(6) } }, Mov { destination: Relative(1), source: Direct(1) }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Direct(2) }, Store { destination_pointer: Relative(1), source: Direct(32836) }, Const { destination: Relative(5), bit_size: Integer(U32), value: 0 }, Const { destination: Relative(6), bit_size: Integer(U32), value: 5 }, Const { destination: Relative(7), bit_size: Integer(U32), value: 1 }, Mov { destination: Relative(2), source: Relative(5) }, Jump { location: 78 }, BinaryIntOp { destination: Relative(8), op: LessThan, bit_size: U32, lhs: Relative(2), rhs: Relative(6) }, JumpIf { condition: Relative(8), location: 116 }, Jump { location: 81 }, Store { destination_pointer: Relative(1), source: Direct(32835) }, Mov { destination: Relative(2), source: Relative(5) }, Jump { location: 84 }, BinaryIntOp { destination: Relative(8), op: LessThan, bit_size: U32, lhs: Relative(2), rhs: Relative(6) }, JumpIf { condition: Relative(8), location: 112 }, Jump { location: 87 }, Load { destination: Relative(8), source_pointer: Relative(1) }, BinaryFieldOp { destination: Relative(9), op: Equals, lhs: Relative(8), rhs: Direct(32836) }, JumpIf { condition: Relative(9), location: 92 }, Const { destination: Relative(10), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(10) } }, Mov { destination: Relative(2), source: Relative(5) }, Jump { location: 94 }, BinaryIntOp { destination: Relative(5), op: LessThan, bit_size: U32, lhs: Relative(2), rhs: Relative(6) }, JumpIf { condition: Relative(5), location: 108 }, Jump { location: 97 }, Load { destination: Relative(2), source_pointer: Relative(1) }, BinaryFieldOp { destination: Relative(1), op: Equals, lhs: Relative(2), rhs: Direct(32836) }, JumpIf { condition: Relative(1), location: 102 }, Const { destination: Relative(5), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(5) } }, Load { destination: Relative(1), source_pointer: Relative(3) }, BinaryFieldOp { destination: Relative(2), op: Equals, lhs: Relative(1), rhs: Relative(4) }, JumpIf { condition: Relative(2), location: 107 }, Const { destination: Relative(3), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(3) } }, Return, Store { destination_pointer: Relative(1), source: Direct(32836) }, BinaryIntOp { destination: Relative(5), op: Add, bit_size: U32, lhs: Relative(2), rhs: Relative(7) }, Mov { destination: Relative(2), source: Relative(5) }, Jump { location: 94 }, Store { destination_pointer: Relative(1), source: Direct(32836) }, BinaryIntOp { destination: Relative(8), op: Add, bit_size: U32, lhs: Relative(2), rhs: Relative(7) }, Mov { destination: Relative(2), source: Relative(8) }, Jump { location: 84 }, Store { destination_pointer: Relative(1), source: Direct(32836) }, BinaryIntOp { destination: Relative(8), op: Add, bit_size: U32, lhs: Relative(2), rhs: Relative(7) }, Mov { destination: Relative(2), source: Relative(8) }, Jump { location: 78 }, Const { destination: Direct(32772), bit_size: Integer(U32), value: 30720 }, BinaryIntOp { destination: Direct(32771), op: LessThan, bit_size: U32, lhs: Direct(0), rhs: Direct(32772) }, JumpIf { condition: Direct(32771), location: 125 }, IndirectConst { destination_pointer: Direct(1), bit_size: Integer(U64), value: 17843811134343075018 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Direct(2) } }, Return, Call { location: 120 }, Return, Call { location: 120 }, Mov { destination: Relative(3), source: Direct(1) }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Direct(2) }, Const { destination: Relative(4), bit_size: Field, value: 0 }, Store { destination_pointer: Relative(3), source: Relative(4) }, BinaryFieldOp { destination: Relative(4), op: Equals, lhs: Relative(1), rhs: Relative(2) }, JumpIf { condition: Relative(4), location: 144 }, Jump { location: 136 }, Store { destination_pointer: Relative(3), source: Direct(32835) }, BinaryFieldOp { destination: Relative(2), op: Equals, lhs: Relative(1), rhs: Direct(32838) }, JumpIf { condition: Relative(2), location: 142 }, Jump { location: 140 }, Store { destination_pointer: Relative(3), source: Direct(32836) }, Jump { location: 146 }, Store { destination_pointer: Relative(3), source: Direct(32837) }, Jump { location: 146 }, Store { destination_pointer: Relative(3), source: Direct(32838) }, Jump { location: 146 }, Load { destination: Relative(1), source_pointer: Relative(3) }, Return]" + "[Const { destination: Direct(2), bit_size: Integer(U32), value: 1 }, Const { destination: Direct(1), bit_size: Integer(U32), value: 32842 }, Const { destination: Direct(0), bit_size: Integer(U32), value: 3 }, Const { destination: Relative(2), bit_size: Integer(U32), value: 1 }, Const { destination: Relative(3), bit_size: Integer(U32), value: 0 }, CalldataCopy { destination_address: Direct(32841), size_address: Relative(2), offset_address: Relative(3) }, Mov { destination: Relative(1), source: Direct(32841) }, Call { location: 12 }, Call { location: 19 }, Const { destination: Relative(1), bit_size: Integer(U32), value: 32842 }, Const { destination: Relative(2), bit_size: Integer(U32), value: 0 }, Stop { return_data: HeapVector { pointer: Relative(1), size: Relative(2) } }, Const { destination: Direct(32835), bit_size: Integer(U32), value: 0 }, Const { destination: Direct(32836), bit_size: Field, value: 0 }, Const { destination: Direct(32837), bit_size: Field, value: 1 }, Const { destination: Direct(32838), bit_size: Field, value: 2 }, Const { destination: Direct(32839), bit_size: Field, value: 15 }, Const { destination: Direct(32840), bit_size: Field, value: 20 }, Return, Call { location: 143 }, Mov { destination: Relative(3), source: Direct(1) }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Direct(2) }, BinaryFieldOp { destination: Relative(4), op: Add, lhs: Relative(1), rhs: Direct(32837) }, Store { destination_pointer: Relative(3), source: Relative(4) }, Const { destination: Relative(1), bit_size: Field, value: 3 }, BinaryFieldOp { destination: Relative(5), op: Equals, lhs: Relative(4), rhs: Relative(1) }, JumpIf { condition: Relative(5), location: 29 }, Const { destination: Relative(6), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(6) } }, Mov { destination: Relative(4), source: Direct(1) }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Direct(2) }, Const { destination: Relative(5), bit_size: Field, value: 7 }, Store { destination_pointer: Relative(4), source: Relative(5) }, Const { destination: Relative(6), bit_size: Integer(U32), value: 7 }, Mov { destination: Relative(7), source: Direct(0) }, BinaryIntOp { destination: Direct(0), op: Add, bit_size: U32, lhs: Direct(0), rhs: Relative(6) }, Call { location: 149 }, Mov { destination: Direct(0), source: Relative(0) }, Const { destination: Relative(6), bit_size: Field, value: 10 }, Const { destination: Relative(8), bit_size: Integer(U32), value: 9 }, Mov { destination: Relative(9), source: Direct(0) }, Mov { destination: Relative(10), source: Relative(1) }, Mov { destination: Relative(11), source: Relative(6) }, BinaryIntOp { destination: Direct(0), op: Add, bit_size: U32, lhs: Direct(0), rhs: Relative(8) }, Call { location: 151 }, Mov { destination: Direct(0), source: Relative(0) }, Mov { destination: Relative(7), source: Relative(10) }, BinaryFieldOp { destination: Relative(8), op: Equals, lhs: Relative(7), rhs: Direct(32838) }, JumpIf { condition: Relative(8), location: 51 }, Const { destination: Relative(9), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(9) } }, Const { destination: Relative(8), bit_size: Integer(U32), value: 9 }, Mov { destination: Relative(9), source: Direct(0) }, Mov { destination: Relative(10), source: Direct(32840) }, Mov { destination: Relative(11), source: Relative(1) }, BinaryIntOp { destination: Direct(0), op: Add, bit_size: U32, lhs: Direct(0), rhs: Relative(8) }, Call { location: 151 }, Mov { destination: Direct(0), source: Relative(0) }, Mov { destination: Relative(7), source: Relative(10) }, BinaryFieldOp { destination: Relative(8), op: Equals, lhs: Relative(7), rhs: Direct(32839) }, JumpIf { condition: Relative(8), location: 63 }, Const { destination: Relative(9), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(9) } }, Const { destination: Relative(8), bit_size: Integer(U32), value: 9 }, Mov { destination: Relative(9), source: Direct(0) }, Mov { destination: Relative(10), source: Relative(1) }, Mov { destination: Relative(11), source: Relative(1) }, BinaryIntOp { destination: Direct(0), op: Add, bit_size: U32, lhs: Direct(0), rhs: Relative(8) }, Call { location: 151 }, Mov { destination: Direct(0), source: Relative(0) }, Mov { destination: Relative(7), source: Relative(10) }, BinaryFieldOp { destination: Relative(8), op: Equals, lhs: Relative(7), rhs: Direct(32840) }, JumpIf { condition: Relative(8), location: 75 }, Const { destination: Relative(9), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(9) } }, Mov { destination: Relative(7), source: Direct(1) }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Direct(2) }, Store { destination_pointer: Relative(7), source: Direct(32838) }, Const { destination: Relative(8), bit_size: Integer(U32), value: 5 }, Const { destination: Relative(9), bit_size: Integer(U32), value: 1 }, Mov { destination: Relative(2), source: Direct(32835) }, Jump { location: 82 }, BinaryIntOp { destination: Relative(10), op: LessThan, bit_size: U32, lhs: Relative(2), rhs: Relative(8) }, JumpIf { condition: Relative(10), location: 139 }, Jump { location: 85 }, Store { destination_pointer: Relative(7), source: Direct(32837) }, Mov { destination: Relative(2), source: Direct(32835) }, Jump { location: 88 }, BinaryIntOp { destination: Relative(10), op: LessThan, bit_size: U32, lhs: Relative(2), rhs: Relative(8) }, JumpIf { condition: Relative(10), location: 135 }, Jump { location: 91 }, Load { destination: Relative(10), source_pointer: Relative(7) }, BinaryFieldOp { destination: Relative(11), op: Equals, lhs: Relative(10), rhs: Direct(32838) }, JumpIf { condition: Relative(11), location: 96 }, Const { destination: Relative(12), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(12) } }, Mov { destination: Relative(2), source: Direct(32835) }, Jump { location: 98 }, BinaryIntOp { destination: Relative(10), op: LessThan, bit_size: U32, lhs: Relative(2), rhs: Relative(8) }, JumpIf { condition: Relative(10), location: 131 }, Jump { location: 101 }, Load { destination: Relative(2), source_pointer: Relative(7) }, BinaryFieldOp { destination: Relative(7), op: Equals, lhs: Relative(2), rhs: Direct(32838) }, JumpIf { condition: Relative(7), location: 106 }, Const { destination: Relative(8), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(8) } }, Load { destination: Relative(2), source_pointer: Relative(4) }, BinaryFieldOp { destination: Relative(4), op: Equals, lhs: Relative(2), rhs: Relative(5) }, JumpIf { condition: Relative(4), location: 111 }, Const { destination: Relative(7), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(7) } }, Load { destination: Relative(2), source_pointer: Relative(3) }, Const { destination: Relative(3), bit_size: Integer(U32), value: 7 }, Mov { destination: Relative(7), source: Direct(0) }, Mov { destination: Relative(8), source: Relative(2) }, Mov { destination: Relative(9), source: Relative(6) }, BinaryIntOp { destination: Direct(0), op: Add, bit_size: U32, lhs: Direct(0), rhs: Relative(3) }, Call { location: 170 }, Mov { destination: Direct(0), source: Relative(0) }, BinaryFieldOp { destination: Relative(3), op: Equals, lhs: Relative(2), rhs: Relative(1) }, JumpIf { condition: Relative(3), location: 123 }, Const { destination: Relative(4), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(4) } }, Const { destination: Relative(2), bit_size: Integer(U32), value: 3 }, Mov { destination: Relative(3), source: Direct(0) }, Mov { destination: Relative(4), source: Relative(1) }, Mov { destination: Relative(5), source: Relative(1) }, BinaryIntOp { destination: Direct(0), op: Add, bit_size: U32, lhs: Direct(0), rhs: Relative(2) }, Call { location: 170 }, Mov { destination: Direct(0), source: Relative(0) }, Return, Store { destination_pointer: Relative(7), source: Direct(32838) }, BinaryIntOp { destination: Relative(10), op: Add, bit_size: U32, lhs: Relative(2), rhs: Relative(9) }, Mov { destination: Relative(2), source: Relative(10) }, Jump { location: 98 }, Store { destination_pointer: Relative(7), source: Direct(32838) }, BinaryIntOp { destination: Relative(10), op: Add, bit_size: U32, lhs: Relative(2), rhs: Relative(9) }, Mov { destination: Relative(2), source: Relative(10) }, Jump { location: 88 }, Store { destination_pointer: Relative(7), source: Direct(32838) }, BinaryIntOp { destination: Relative(10), op: Add, bit_size: U32, lhs: Relative(2), rhs: Relative(9) }, Mov { destination: Relative(2), source: Relative(10) }, Jump { location: 82 }, Const { destination: Direct(32772), bit_size: Integer(U32), value: 30720 }, BinaryIntOp { destination: Direct(32771), op: LessThan, bit_size: U32, lhs: Direct(0), rhs: Direct(32772) }, JumpIf { condition: Direct(32771), location: 148 }, IndirectConst { destination_pointer: Direct(1), bit_size: Integer(U64), value: 17843811134343075018 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Direct(2) } }, Return, Call { location: 143 }, Return, Call { location: 143 }, Mov { destination: Relative(3), source: Direct(1) }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Direct(2) }, Store { destination_pointer: Relative(3), source: Direct(32836) }, BinaryFieldOp { destination: Relative(4), op: Equals, lhs: Relative(1), rhs: Relative(2) }, JumpIf { condition: Relative(4), location: 166 }, Jump { location: 158 }, Store { destination_pointer: Relative(3), source: Direct(32837) }, BinaryFieldOp { destination: Relative(2), op: Equals, lhs: Relative(1), rhs: Direct(32840) }, JumpIf { condition: Relative(2), location: 164 }, Jump { location: 162 }, Store { destination_pointer: Relative(3), source: Direct(32838) }, Jump { location: 168 }, Store { destination_pointer: Relative(3), source: Direct(32839) }, Jump { location: 168 }, Store { destination_pointer: Relative(3), source: Direct(32840) }, Jump { location: 168 }, Load { destination: Relative(1), source_pointer: Relative(3) }, Return, Call { location: 143 }, Mov { destination: Relative(3), source: Direct(1) }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Direct(2) }, Store { destination_pointer: Relative(3), source: Direct(32836) }, Mov { destination: Relative(4), source: Direct(1) }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Direct(2) }, Store { destination_pointer: Relative(4), source: Direct(32835) }, BinaryFieldOp { destination: Relative(5), op: Equals, lhs: Relative(1), rhs: Relative(2) }, Const { destination: Relative(1), bit_size: Field, value: 52 }, Const { destination: Relative(2), bit_size: Integer(U32), value: 69 }, Const { destination: Relative(6), bit_size: Field, value: 12 }, Const { destination: Relative(7), bit_size: Integer(U32), value: 28 }, JumpIf { condition: Relative(5), location: 187 }, Jump { location: 184 }, Store { destination_pointer: Relative(3), source: Relative(6) }, Store { destination_pointer: Relative(4), source: Relative(7) }, Jump { location: 190 }, Store { destination_pointer: Relative(3), source: Relative(1) }, Store { destination_pointer: Relative(4), source: Relative(2) }, Jump { location: 190 }, JumpIf { condition: Relative(5), location: 203 }, Jump { location: 192 }, Load { destination: Relative(1), source_pointer: Relative(3) }, BinaryFieldOp { destination: Relative(2), op: Equals, lhs: Relative(1), rhs: Relative(6) }, JumpIf { condition: Relative(2), location: 197 }, Const { destination: Relative(3), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(3) } }, Load { destination: Relative(1), source_pointer: Relative(4) }, BinaryIntOp { destination: Relative(2), op: Equals, bit_size: U32, lhs: Relative(1), rhs: Relative(7) }, JumpIf { condition: Relative(2), location: 202 }, Const { destination: Relative(3), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(3) } }, Jump { location: 214 }, Load { destination: Relative(5), source_pointer: Relative(3) }, BinaryFieldOp { destination: Relative(3), op: Equals, lhs: Relative(5), rhs: Relative(1) }, JumpIf { condition: Relative(3), location: 208 }, Const { destination: Relative(6), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(6) } }, Load { destination: Relative(1), source_pointer: Relative(4) }, BinaryIntOp { destination: Relative(3), op: Equals, bit_size: U32, lhs: Relative(1), rhs: Relative(2) }, JumpIf { condition: Relative(3), location: 213 }, Const { destination: Relative(4), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(4) } }, Jump { location: 214 }, Return]" ], - "debug_symbols": "tZdLbuMwDIbv4nUWokhKYq4yKIo0dYsAhhO4yQCDIncfMnq0HcBeCJhNPsYWf5EiJdufw+v4cnt/Ps1v549h/+tzeFlO03R6f57Ox8P1dJ716ufg7AfSsPe7AWTY427wLgMyfAZmUAZnhGHPipihKkEhD6DLgAyfoSpJQRmcETJiRsqQB8hlQIaqiAIzKIMzVAVAGQtToWSyK4RCX4iFqga6CMyFoTAWmh4pJTO4Qij0hVhIhVxoerpKIRamQsmMpheVUGh6mnO0cZpf0uveKVXXa7xJdbzGlax2WoskmeIKodDG6/xi43UesfFaCpFMcK4aUA2d2iczNBcvZlA1uBqhGqqHzgzrHg0MwDrG2gmsZ9AMHYxkhgaBGgRYk6DNZW2SDaiGr4a5RzPM3eKxFkGb1NqCbFLrCLJJrRnIJrU+ILzfd0Pt8+frMo7W5t8aX7fD5bCM83XYz7dp2g2/D9PtMejjcpgfvB4WvauTjPOrUgXfTtNo1n335e3WXW0JH7705cw/vWHdG8DyevirmdYUNuZnLP4sHd4+UHH3kdb8aSN+5Fjjx9ATfyIpAimEDn/BWgCJfs0/rvtjjFwEMEroUUiupoAJeqogseag23O1DOC2YpBQYxCIXRKCrkkQdKShR4predDqUgKuS5Bra0kOXZ8EYZNg6sqDfcsjrhYUwkYQ8HUu6DHYJeGpllTN2CVBoZ4uavouCfF1g6uZ+iSYmgRzjwR7qW3B6LqiYGwHBeNGc25KpNAkUldFOLatzrFTIrlaEU7AXf2duD103GoQPv5XieDawRucYNdSBGgFCdC3miG2zgqdBQGsiajZ11kgrS2865KgIG2vB+nb66m9TFBaPy62niHetYfpRh6bCtyeQp77FCI2hdhz/iPGupRq9rzUIPmmQL5rJdnXZ5CaXVmwUFOQrpUM0FYy/JPFk/47HE/Lj+/Mu2ktp8PLNJa/b7f5+O3u9c+l3qnfqZflfBxfb8toSt8+VvX3F+j7BHh+utt8fwE=", + "debug_symbols": "nVhBbiM5DPxLn3OQREqU8pXBIHASZ2DAcAKPvcAi8N+XZYnyzALdB15SlbRZIsUSo/b38r5/vf56OZw+Pn8vzz++l9fz4Xg8/Ho5fr7tLofPk/71ewn4kdLynJ6WRB14eSaF3KF0kA61Q7sDhQ5xec4KqYOqFAXukDuUDtJBVapCuwOHDrFD6kAduEPuUDqoSlOoHdodcuigKjEqpoE0kAfmgWWgDKwDVS3qJpQwMA5MA6HHijwwDywDZWAd2DpKGAg93SVJA2kgD4SeKJaB0NOaKz6v9VV9noKi6ifNt6le0rwaWqi9aDSQB+aB+LyuHwMCMggiCggZYSPZiGaRKoimkRpINdIGicEIlAVElSmAkBE2ko0UI2KkGoG5tLSYgpFoJBmBcgJhI9lIMSJGqpE2CBxLBAJBbAt8StgWOJVQO9xJKAf+JGwCPMWoFKbqhI1oeEby8FFGhjBSxlpwTsZasEzGWvBKxlowScZacAVBB7bohIywkWykGNECGYtWpIFF4Y5O8Airwyd3AoMw0oBDGGnAIp1kI8WIGEE4Um2tkxSCkWgEggUEggKSjRQjYqQagaDuaoJ/OolGkGq93Z4WG1Uvl/N+j0n1x+zSifa1O+9Pl+X5dD0en5Z/dsfr/UO/v3anO152Z32qO7Q/vSuq4MfhuAe7PT2iw3oovH+P5Udw/js6rkerXduIV8OWNYWN9eGbe3xujuhUeIQn4bV43sif0d+eP2dP/pVtA2rxxDeyBjRJa/GyHk+12A5SrexSaGIKLYinBrEadPauphA3FKhVnj4M2SPBIT6snDxm0v8XYdbBq82MtJXE3EvWce+SiBj/Q4KTqw5M5VGHrO5ELBtJJDztSaQoLgmi2VKi7JLI83BxzsEjkUO0A660+CQ4TQkmlwRVs0Wm5suCk3UkM7FPQnhKiKsjWYecSVSvRJsdaYFc/q5zaMf1gZU2Zp5IsJ6KpOyRKHEO3hJr9NQRI8062KeQZSoUn0KZs1tvSa6GSpi2kuCUKPN8iNNWKc2bREq+85HqNHdqLgkWmRNLqmticeM5/9v60NvoaSGZzqT1a9GWAjdzRdGZ51GQx+mQ6jnlEqYnJNTqUYjRjCn6puVSmLcz0Rcgl8LshcTmyoHaVODouWIK89xJLuxSqHNccvPcrSjNKmjjbG0p0OyF3ix8CiVOheK5WRFnO97Erus+5TAVcvT4QYuwW6pSVxVldlOpayclzJ2U/1XxU3/bvR3Of30Jd4PW+bB7Pe7Hrx/X09sfTy//ftkT+xLv6/z5tn+/nvdQenyTh5fpH1Hf8yPXnzes9x8=", "file_map": { "50": { - "source": "fn main(mut x: Field) {\n add1(&mut x);\n assert(x == 3);\n let mut s = S { y: x };\n s.add2();\n assert(s.y == 5);\n // Regression for #1946: Method resolution error when calling &mut methods with a variable of type &mut T\n let s_ref = &mut s;\n s_ref.add2();\n assert(s.y == 7);\n // Test that normal mutable variables are still copied\n let mut a = 0;\n mutate_copy(a);\n assert(a == 0);\n // Test something 3 allocations deep\n let mut nested_allocations = Nested { y: &mut &mut 0 };\n add1(*nested_allocations.y);\n assert(**nested_allocations.y == 1);\n // Test nested struct allocations with a mutable reference to an array.\n let mut c = C { foo: 0, bar: &mut C2 { array: &mut [1, 2] } };\n *c.bar.array = [3, 4];\n assert(*c.bar.array == [3, 4]);\n regression_1887();\n regression_2054();\n regression_2030();\n regression_2255();\n regression_6443();\n assert(x == 3);\n regression_2218_if_inner_if(x, 10);\n regression_2218_if_inner_else(20, x);\n regression_2218_else(x, 3);\n regression_2218_loop(x, 10);\n regression_2560(s_ref);\n}\n\nfn add1(x: &mut Field) {\n *x += 1;\n}\n\nstruct S {\n y: Field,\n}\n\nstruct Nested {\n y: &mut &mut Field,\n}\n\nstruct C {\n foo: Field,\n bar: &mut C2,\n}\n\nstruct C2 {\n array: &mut [Field; 2],\n}\n\nimpl S {\n fn add2(&mut self) {\n self.y += 2;\n }\n\n fn get_y(self) -> Field {\n self.y\n }\n}\n\nfn mutate_copy(mut a: Field) {\n a = 7;\n}\n// Previously the `foo.bar` in `foo.bar.mutate()` would insert an automatic dereference\n// of `foo` which caused the method to wrongly be mutating a copy of bar rather than the original.\nfn regression_1887() {\n let foo = &mut Foo { bar: Bar { x: 0 } };\n foo.bar.mutate();\n assert(foo.bar.x == 32);\n}\n\nstruct Foo {\n bar: Bar,\n}\nstruct Bar {\n x: Field,\n}\n\nimpl Bar {\n fn mutate(&mut self) {\n self.x = 32;\n }\n}\n// Ensure that mutating a variable does not also mutate its copy\nfn regression_2054() {\n let mut x = 2;\n let z = x;\n\n x += 1;\n assert(z == 2);\n}\n// The compiler was still trying to convert an LValue from an array of structs to struct of arrays indexing,\n// even though this conversion was mostly removed elsewhere.\nfn regression_2030() {\n let ref = &mut 0;\n let mut array = [ref, ref];\n let _ = *array[0];\n *array[0] = 1;\n}\n\n// The `mut x: &mut ...` caught a bug handling lvalues where a double-dereference would occur internally\n// in one step rather than being tracked by two separate steps. This lead to assigning the 1 value to the\n// incorrect outer `mut` reference rather than the correct `&mut` reference.\nfn regression_2255() {\n let x = &mut 0;\n regression_2255_helper(x);\n assert(*x == 1);\n}\n\nfn regression_2255_helper(mut x: &mut Field) {\n *x = 1;\n}\n\n// Similar to `regression_2255` but without the double-dereferencing.\n// The test checks that `mem2reg` does not eliminate storing to a reference passed as a parameter.\nfn regression_6443() {\n let x = &mut 0;\n regression_6443_helper(x);\n assert(*x == 1);\n}\n\nfn regression_6443_helper(x: &mut Field) {\n *x = 1;\n}\n\nfn regression_2218(x: Field, y: Field) -> Field {\n let q = &mut &mut 0;\n let q1 = *q;\n let q2 = *q;\n\n if x != y {\n *q1 = 1;\n // Make sure that we correct load reference aliases through multiple blocks\n if x != 20 {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n } else {\n *q2 = 15;\n assert(*q1 == 15);\n }\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n // Have to assign value to return it\n let value = *q1;\n value\n}\n\nfn regression_2218_if_inner_if(x: Field, y: Field) {\n let value = regression_2218(x, y);\n assert(value == 2);\n}\n\nfn regression_2218_if_inner_else(x: Field, y: Field) {\n let value = regression_2218(x, y);\n assert(value == 15);\n}\n\nfn regression_2218_else(x: Field, y: Field) {\n let value = regression_2218(x, y);\n assert(value == 20);\n}\n\nfn regression_2218_loop(x: Field, y: Field) {\n let q = &mut &mut 0;\n let q1 = *q;\n let q2 = *q;\n\n for _ in 0..1 {\n if x != y {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n }\n assert(*q1 == 2);\n\n for _ in 0..1 {\n for _ in 0..5 {\n if x != y {\n *q1 = 1;\n // Make sure that we correct load reference aliases through multiple blocks\n if x != 20 {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n }\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n }\n if x != y {\n *q1 = 1;\n for _ in 0..5 {\n // Make sure that we correct load reference aliases through multiple blocks\n if x != 20 {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n }\n }\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n }\n assert(*q1 == 2);\n\n if x != y {\n for _ in 0..5 {\n if x != y {\n *q1 = 1;\n // Make sure that we correct load reference aliases through multiple blocks\n if x != 20 {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n }\n }\n }\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n assert(*q1 == 2);\n}\n// This is more a feature test than a proper regression.\n// Before, we never automatically dereferenced objects in method calls to their value types.\n// Now, we insert as many `*` as necessary to get to `S`.\nfn regression_2560(s_ref: &mut S) {\n assert(s_ref.get_y() == 7);\n}\n", + "source": "fn main(mut x: Field) {\n add1(&mut x);\n assert(x == 3);\n let mut s = S { y: x };\n s.add2();\n assert(s.y == 5);\n // Regression for #1946: Method resolution error when calling &mut methods with a variable of type &mut T\n let s_ref = &mut s;\n s_ref.add2();\n assert(s.y == 7);\n // Test that normal mutable variables are still copied\n let mut a = 0;\n mutate_copy(a);\n assert(a == 0);\n // Test something 3 allocations deep\n let mut nested_allocations = Nested { y: &mut &mut 0 };\n add1(*nested_allocations.y);\n assert(**nested_allocations.y == 1);\n // Test nested struct allocations with a mutable reference to an array.\n let mut c = C { foo: 0, bar: &mut C2 { array: &mut [1, 2] } };\n *c.bar.array = [3, 4];\n assert(*c.bar.array == [3, 4]);\n regression_1887();\n regression_2054();\n regression_2030();\n regression_2255();\n regression_6443();\n assert(x == 3);\n regression_2218_if_inner_if(x, 10);\n regression_2218_if_inner_else(20, x);\n regression_2218_else(x, 3);\n regression_2218_loop(x, 10);\n regression_2560(s_ref);\n nested_struct_aliases(x, 10);\n assert_eq(x, 3);\n nested_struct_aliases(x, 3);\n}\n\nfn add1(x: &mut Field) {\n *x += 1;\n}\n\nstruct S {\n y: Field,\n}\n\nstruct Nested {\n y: &mut &mut Field,\n}\n\nstruct C {\n foo: Field,\n bar: &mut C2,\n}\n\nstruct C2 {\n array: &mut [Field; 2],\n}\n\nimpl S {\n fn add2(&mut self) {\n self.y += 2;\n }\n\n fn get_y(self) -> Field {\n self.y\n }\n}\n\nfn mutate_copy(mut a: Field) {\n a = 7;\n}\n// Previously the `foo.bar` in `foo.bar.mutate()` would insert an automatic dereference\n// of `foo` which caused the method to wrongly be mutating a copy of bar rather than the original.\nfn regression_1887() {\n let foo = &mut Foo { bar: Bar { x: 0 } };\n foo.bar.mutate();\n assert(foo.bar.x == 32);\n}\n\nstruct Foo {\n bar: Bar,\n}\nstruct Bar {\n x: Field,\n}\n\nimpl Bar {\n fn mutate(&mut self) {\n self.x = 32;\n }\n}\n// Ensure that mutating a variable does not also mutate its copy\nfn regression_2054() {\n let mut x = 2;\n let z = x;\n\n x += 1;\n assert(z == 2);\n}\n// The compiler was still trying to convert an LValue from an array of structs to struct of arrays indexing,\n// even though this conversion was mostly removed elsewhere.\nfn regression_2030() {\n let ref = &mut 0;\n let mut array = [ref, ref];\n let _ = *array[0];\n *array[0] = 1;\n}\n\n// The `mut x: &mut ...` caught a bug handling lvalues where a double-dereference would occur internally\n// in one step rather than being tracked by two separate steps. This lead to assigning the 1 value to the\n// incorrect outer `mut` reference rather than the correct `&mut` reference.\nfn regression_2255() {\n let x = &mut 0;\n regression_2255_helper(x);\n assert(*x == 1);\n}\n\nfn regression_2255_helper(mut x: &mut Field) {\n *x = 1;\n}\n\n// Similar to `regression_2255` but without the double-dereferencing.\n// The test checks that `mem2reg` does not eliminate storing to a reference passed as a parameter.\nfn regression_6443() {\n let x = &mut 0;\n regression_6443_helper(x);\n assert(*x == 1);\n}\n\nfn regression_6443_helper(x: &mut Field) {\n *x = 1;\n}\n\nfn regression_2218(x: Field, y: Field) -> Field {\n let q = &mut &mut 0;\n let q1 = *q;\n let q2 = *q;\n\n if x != y {\n *q1 = 1;\n // Make sure that we correct load reference aliases through multiple blocks\n if x != 20 {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n } else {\n *q2 = 15;\n assert(*q1 == 15);\n }\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n // Have to assign value to return it\n let value = *q1;\n value\n}\n\nfn regression_2218_if_inner_if(x: Field, y: Field) {\n let value = regression_2218(x, y);\n assert(value == 2);\n}\n\nfn regression_2218_if_inner_else(x: Field, y: Field) {\n let value = regression_2218(x, y);\n assert(value == 15);\n}\n\nfn regression_2218_else(x: Field, y: Field) {\n let value = regression_2218(x, y);\n assert(value == 20);\n}\n\nfn regression_2218_loop(x: Field, y: Field) {\n let q = &mut &mut 0;\n let q1 = *q;\n let q2 = *q;\n\n for _ in 0..1 {\n if x != y {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n }\n assert(*q1 == 2);\n\n for _ in 0..1 {\n for _ in 0..5 {\n if x != y {\n *q1 = 1;\n // Make sure that we correct load reference aliases through multiple blocks\n if x != 20 {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n }\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n }\n if x != y {\n *q1 = 1;\n for _ in 0..5 {\n // Make sure that we correct load reference aliases through multiple blocks\n if x != 20 {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n }\n }\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n }\n assert(*q1 == 2);\n\n if x != y {\n for _ in 0..5 {\n if x != y {\n *q1 = 1;\n // Make sure that we correct load reference aliases through multiple blocks\n if x != 20 {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n }\n }\n }\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n assert(*q1 == 2);\n}\n// This is more a feature test than a proper regression.\n// Before, we never automatically dereferenced objects in method calls to their value types.\n// Now, we insert as many `*` as necessary to get to `S`.\nfn regression_2560(s_ref: &mut S) {\n assert(s_ref.get_y() == 7);\n}\n\nstruct MyStruct {\n a: Field,\n b: u32,\n}\n\nstruct Outer {\n inner: MyStruct,\n}\n\nfn nested_struct_aliases(x: Field, y: Field) {\n let mut var = Outer { inner: MyStruct { a: 0, b: 0 } };\n let ref_outer = &mut var;\n let ref_inner1 = &mut ref_outer.inner;\n let ref_inner2 = &mut var.inner;\n\n if x != y {\n (*ref_inner1).a = 5;\n (*ref_inner1).b = 7;\n (*ref_inner2).a = 3;\n (*ref_inner2).b = 10;\n\n for _ in 0..3 {\n (*ref_inner1).a += 1;\n (*ref_inner1).b += 2;\n (*ref_inner2).a += 2;\n (*ref_inner2).b += 4;\n }\n } else {\n (*ref_inner2).a = 20;\n (*ref_inner2).b = 15;\n (*ref_inner1).a = 25;\n (*ref_inner1).b = 30;\n\n for _ in 0..3 {\n (*ref_inner2).a += 5;\n (*ref_inner2).b += 3;\n (*ref_inner1).a += 4;\n (*ref_inner1).b += 10;\n }\n }\n\n if x != y {\n assert(var.inner.a == 12);\n assert(var.inner.b == 28);\n assert(ref_inner1.a == 12);\n assert(ref_inner1.b == 28);\n assert(ref_inner2.a == 12);\n assert(ref_inner2.b == 28);\n assert(ref_outer.inner.a == 12);\n assert(ref_outer.inner.b == 28);\n } else {\n assert(var.inner.a == 52);\n assert(var.inner.b == 69);\n assert(ref_inner1.a == 52);\n assert(ref_inner1.b == 69);\n assert(ref_inner2.a == 52);\n assert(ref_inner2.b == 69);\n assert(ref_outer.inner.a == 52);\n assert(ref_outer.inner.b == 69);\n }\n}\n", "path": "" } }, diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/references/execute__tests__force_brillig_true_inliner_9223372036854775807.snap b/tooling/nargo_cli/tests/snapshots/execution_success/references/execute__tests__force_brillig_true_inliner_9223372036854775807.snap index 90c27dda326..aefffc17b98 100644 --- a/tooling/nargo_cli/tests/snapshots/execution_success/references/execute__tests__force_brillig_true_inliner_9223372036854775807.snap +++ b/tooling/nargo_cli/tests/snapshots/execution_success/references/execute__tests__force_brillig_true_inliner_9223372036854775807.snap @@ -31,12 +31,12 @@ expression: artifact "return value indices : []", "BRILLIG CALL func 0: inputs: [EXPR [ (1, _0) 0 ]], outputs: []", "unconstrained func 0", - "[Const { destination: Direct(2), bit_size: Integer(U32), value: 1 }, Const { destination: Direct(1), bit_size: Integer(U32), value: 32837 }, Const { destination: Direct(0), bit_size: Integer(U32), value: 3 }, Const { destination: Relative(2), bit_size: Integer(U32), value: 1 }, Const { destination: Relative(3), bit_size: Integer(U32), value: 0 }, CalldataCopy { destination_address: Direct(32836), size_address: Relative(2), offset_address: Relative(3) }, Mov { destination: Relative(1), source: Direct(32836) }, Call { location: 12 }, Call { location: 13 }, Const { destination: Relative(1), bit_size: Integer(U32), value: 32837 }, Const { destination: Relative(2), bit_size: Integer(U32), value: 0 }, Stop { return_data: HeapVector { pointer: Relative(1), size: Relative(2) } }, Return, Call { location: 77 }, Const { destination: Relative(2), bit_size: Field, value: 1 }, BinaryFieldOp { destination: Relative(3), op: Add, lhs: Relative(1), rhs: Relative(2) }, Const { destination: Relative(1), bit_size: Field, value: 3 }, BinaryFieldOp { destination: Relative(4), op: Equals, lhs: Relative(3), rhs: Relative(1) }, JumpIf { condition: Relative(4), location: 21 }, Const { destination: Relative(5), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(5) } }, Mov { destination: Relative(1), source: Direct(1) }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Direct(2) }, Const { destination: Relative(3), bit_size: Field, value: 7 }, Store { destination_pointer: Relative(1), source: Relative(3) }, Jump { location: 26 }, Mov { destination: Relative(5), source: Direct(1) }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Direct(2) }, Const { destination: Relative(6), bit_size: Field, value: 2 }, Store { destination_pointer: Relative(5), source: Relative(6) }, Const { destination: Relative(7), bit_size: Integer(U32), value: 0 }, Const { destination: Relative(8), bit_size: Integer(U32), value: 5 }, Const { destination: Relative(9), bit_size: Integer(U32), value: 1 }, Mov { destination: Relative(4), source: Relative(7) }, Jump { location: 35 }, BinaryIntOp { destination: Relative(10), op: LessThan, bit_size: U32, lhs: Relative(4), rhs: Relative(8) }, JumpIf { condition: Relative(10), location: 73 }, Jump { location: 38 }, Store { destination_pointer: Relative(5), source: Relative(2) }, Mov { destination: Relative(4), source: Relative(7) }, Jump { location: 41 }, BinaryIntOp { destination: Relative(2), op: LessThan, bit_size: U32, lhs: Relative(4), rhs: Relative(8) }, JumpIf { condition: Relative(2), location: 69 }, Jump { location: 44 }, Load { destination: Relative(4), source_pointer: Relative(5) }, BinaryFieldOp { destination: Relative(10), op: Equals, lhs: Relative(4), rhs: Relative(6) }, JumpIf { condition: Relative(10), location: 49 }, Const { destination: Relative(11), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(11) } }, Mov { destination: Relative(2), source: Relative(7) }, Jump { location: 51 }, BinaryIntOp { destination: Relative(4), op: LessThan, bit_size: U32, lhs: Relative(2), rhs: Relative(8) }, JumpIf { condition: Relative(4), location: 65 }, Jump { location: 54 }, Load { destination: Relative(2), source_pointer: Relative(5) }, BinaryFieldOp { destination: Relative(4), op: Equals, lhs: Relative(2), rhs: Relative(6) }, JumpIf { condition: Relative(4), location: 59 }, Const { destination: Relative(5), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(5) } }, Load { destination: Relative(2), source_pointer: Relative(1) }, BinaryFieldOp { destination: Relative(1), op: Equals, lhs: Relative(2), rhs: Relative(3) }, JumpIf { condition: Relative(1), location: 64 }, Const { destination: Relative(4), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(4) } }, Return, Store { destination_pointer: Relative(5), source: Relative(6) }, BinaryIntOp { destination: Relative(4), op: Add, bit_size: U32, lhs: Relative(2), rhs: Relative(9) }, Mov { destination: Relative(2), source: Relative(4) }, Jump { location: 51 }, Store { destination_pointer: Relative(5), source: Relative(6) }, BinaryIntOp { destination: Relative(2), op: Add, bit_size: U32, lhs: Relative(4), rhs: Relative(9) }, Mov { destination: Relative(4), source: Relative(2) }, Jump { location: 41 }, Store { destination_pointer: Relative(5), source: Relative(6) }, BinaryIntOp { destination: Relative(10), op: Add, bit_size: U32, lhs: Relative(4), rhs: Relative(9) }, Mov { destination: Relative(4), source: Relative(10) }, Jump { location: 35 }, Const { destination: Direct(32772), bit_size: Integer(U32), value: 30720 }, BinaryIntOp { destination: Direct(32771), op: LessThan, bit_size: U32, lhs: Direct(0), rhs: Direct(32772) }, JumpIf { condition: Direct(32771), location: 82 }, IndirectConst { destination_pointer: Direct(1), bit_size: Integer(U64), value: 17843811134343075018 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Direct(2) } }, Return]" + "[Const { destination: Direct(2), bit_size: Integer(U32), value: 1 }, Const { destination: Direct(1), bit_size: Integer(U32), value: 32837 }, Const { destination: Direct(0), bit_size: Integer(U32), value: 3 }, Const { destination: Relative(2), bit_size: Integer(U32), value: 1 }, Const { destination: Relative(3), bit_size: Integer(U32), value: 0 }, CalldataCopy { destination_address: Direct(32836), size_address: Relative(2), offset_address: Relative(3) }, Mov { destination: Relative(1), source: Direct(32836) }, Call { location: 12 }, Call { location: 13 }, Const { destination: Relative(1), bit_size: Integer(U32), value: 32837 }, Const { destination: Relative(2), bit_size: Integer(U32), value: 0 }, Stop { return_data: HeapVector { pointer: Relative(1), size: Relative(2) } }, Return, Call { location: 130 }, Mov { destination: Relative(2), source: Direct(1) }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Direct(2) }, Const { destination: Relative(3), bit_size: Field, value: 1 }, BinaryFieldOp { destination: Relative(4), op: Add, lhs: Relative(1), rhs: Relative(3) }, Store { destination_pointer: Relative(2), source: Relative(4) }, Const { destination: Relative(1), bit_size: Field, value: 3 }, BinaryFieldOp { destination: Relative(5), op: Equals, lhs: Relative(4), rhs: Relative(1) }, JumpIf { condition: Relative(5), location: 24 }, Const { destination: Relative(6), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(6) } }, Mov { destination: Relative(4), source: Direct(1) }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Direct(2) }, Const { destination: Relative(5), bit_size: Field, value: 7 }, Store { destination_pointer: Relative(4), source: Relative(5) }, Jump { location: 29 }, Mov { destination: Relative(7), source: Direct(1) }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Direct(2) }, Const { destination: Relative(8), bit_size: Field, value: 2 }, Store { destination_pointer: Relative(7), source: Relative(8) }, Const { destination: Relative(9), bit_size: Integer(U32), value: 0 }, Const { destination: Relative(10), bit_size: Integer(U32), value: 5 }, Const { destination: Relative(11), bit_size: Integer(U32), value: 1 }, Mov { destination: Relative(6), source: Relative(9) }, Jump { location: 38 }, BinaryIntOp { destination: Relative(12), op: LessThan, bit_size: U32, lhs: Relative(6), rhs: Relative(10) }, JumpIf { condition: Relative(12), location: 126 }, Jump { location: 41 }, Store { destination_pointer: Relative(7), source: Relative(3) }, Mov { destination: Relative(6), source: Relative(9) }, Jump { location: 44 }, BinaryIntOp { destination: Relative(3), op: LessThan, bit_size: U32, lhs: Relative(6), rhs: Relative(10) }, JumpIf { condition: Relative(3), location: 122 }, Jump { location: 47 }, Load { destination: Relative(6), source_pointer: Relative(7) }, BinaryFieldOp { destination: Relative(12), op: Equals, lhs: Relative(6), rhs: Relative(8) }, JumpIf { condition: Relative(12), location: 52 }, Const { destination: Relative(13), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(13) } }, Mov { destination: Relative(3), source: Relative(9) }, Jump { location: 54 }, BinaryIntOp { destination: Relative(6), op: LessThan, bit_size: U32, lhs: Relative(3), rhs: Relative(10) }, JumpIf { condition: Relative(6), location: 118 }, Jump { location: 57 }, Load { destination: Relative(3), source_pointer: Relative(7) }, BinaryFieldOp { destination: Relative(6), op: Equals, lhs: Relative(3), rhs: Relative(8) }, JumpIf { condition: Relative(6), location: 62 }, Const { destination: Relative(7), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(7) } }, Load { destination: Relative(3), source_pointer: Relative(4) }, BinaryFieldOp { destination: Relative(4), op: Equals, lhs: Relative(3), rhs: Relative(5) }, JumpIf { condition: Relative(4), location: 67 }, Const { destination: Relative(6), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(6) } }, Load { destination: Relative(3), source_pointer: Relative(2) }, Mov { destination: Relative(2), source: Direct(1) }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Direct(2) }, Const { destination: Relative(4), bit_size: Field, value: 0 }, Store { destination_pointer: Relative(2), source: Relative(4) }, Mov { destination: Relative(4), source: Direct(1) }, BinaryIntOp { destination: Direct(1), op: Add, bit_size: U32, lhs: Direct(1), rhs: Direct(2) }, Store { destination_pointer: Relative(4), source: Relative(9) }, Const { destination: Relative(5), bit_size: Field, value: 10 }, BinaryFieldOp { destination: Relative(6), op: Equals, lhs: Relative(3), rhs: Relative(5) }, Const { destination: Relative(5), bit_size: Field, value: 52 }, Const { destination: Relative(7), bit_size: Integer(U32), value: 69 }, Const { destination: Relative(8), bit_size: Field, value: 12 }, Const { destination: Relative(9), bit_size: Integer(U32), value: 28 }, JumpIf { condition: Relative(6), location: 86 }, Jump { location: 83 }, Store { destination_pointer: Relative(2), source: Relative(8) }, Store { destination_pointer: Relative(4), source: Relative(9) }, Jump { location: 89 }, Store { destination_pointer: Relative(2), source: Relative(5) }, Store { destination_pointer: Relative(4), source: Relative(7) }, Jump { location: 89 }, JumpIf { condition: Relative(6), location: 102 }, Jump { location: 91 }, Load { destination: Relative(5), source_pointer: Relative(2) }, Load { destination: Relative(2), source_pointer: Relative(4) }, BinaryFieldOp { destination: Relative(4), op: Equals, lhs: Relative(5), rhs: Relative(8) }, JumpIf { condition: Relative(4), location: 97 }, Const { destination: Relative(6), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(6) } }, BinaryIntOp { destination: Relative(4), op: Equals, bit_size: U32, lhs: Relative(2), rhs: Relative(9) }, JumpIf { condition: Relative(4), location: 101 }, Const { destination: Relative(5), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(5) } }, Jump { location: 113 }, Load { destination: Relative(6), source_pointer: Relative(2) }, Load { destination: Relative(2), source_pointer: Relative(4) }, BinaryFieldOp { destination: Relative(4), op: Equals, lhs: Relative(6), rhs: Relative(5) }, JumpIf { condition: Relative(4), location: 108 }, Const { destination: Relative(8), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(8) } }, BinaryIntOp { destination: Relative(4), op: Equals, bit_size: U32, lhs: Relative(2), rhs: Relative(7) }, JumpIf { condition: Relative(4), location: 112 }, Const { destination: Relative(5), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(5) } }, Jump { location: 113 }, BinaryFieldOp { destination: Relative(2), op: Equals, lhs: Relative(3), rhs: Relative(1) }, JumpIf { condition: Relative(2), location: 117 }, Const { destination: Relative(4), bit_size: Integer(U32), value: 0 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Relative(4) } }, Return, Store { destination_pointer: Relative(7), source: Relative(8) }, BinaryIntOp { destination: Relative(6), op: Add, bit_size: U32, lhs: Relative(3), rhs: Relative(11) }, Mov { destination: Relative(3), source: Relative(6) }, Jump { location: 54 }, Store { destination_pointer: Relative(7), source: Relative(8) }, BinaryIntOp { destination: Relative(3), op: Add, bit_size: U32, lhs: Relative(6), rhs: Relative(11) }, Mov { destination: Relative(6), source: Relative(3) }, Jump { location: 44 }, Store { destination_pointer: Relative(7), source: Relative(8) }, BinaryIntOp { destination: Relative(12), op: Add, bit_size: U32, lhs: Relative(6), rhs: Relative(11) }, Mov { destination: Relative(6), source: Relative(12) }, Jump { location: 38 }, Const { destination: Direct(32772), bit_size: Integer(U32), value: 30720 }, BinaryIntOp { destination: Direct(32771), op: LessThan, bit_size: U32, lhs: Direct(0), rhs: Direct(32772) }, JumpIf { condition: Direct(32771), location: 135 }, IndirectConst { destination_pointer: Direct(1), bit_size: Integer(U64), value: 17843811134343075018 }, Trap { revert_data: HeapVector { pointer: Direct(1), size: Direct(2) } }, Return]" ], - "debug_symbols": "tZbLbrMwEIXfxWsWHl/GNq9SVRFJSIWESEThl35FvHuPg03SSnRhqRs+g33ODOOLfBfn9jh/HLrhcv0U9dtdHMeu77uPQ389NVN3HfD1LmR8kBG1qgTZFSxqDbgVfkV4QMkVtEKt0KK2gFkBuQPcCsg9EB7QiBAAfCRZCQMbIhBKQmSDboKh4USX6FfaON6AcTxC2TieQU50iT4RUQlhGVkT4jIlqkSdGH8c+TB8FPJh6BTycdApxHUYpxDXxTrZZalEruFhGts2lvClqCj1rRnbYRL1MPd9Jf41/fwY9HlrhgenZkQvIrbDGYThpevb2Fqqp1ruS5VPWvMU2+9q2lcTGUp6NP2ewy/xrU56GwrUik2SK2f29OaX/LV1OX/NJfmTtCo7SLf7D7zvYOg5B6SKHJTh7KCMK3EwnOcRTVXiEFSuJJq+yMGazcHaAgerQsirScuSHKzWfnMwXOTgeXPwJXNhndtycGUOXua5sJ5s0ar2dtvXcjcHcn9qwdJlC5ZBl1SCaZsNpqJastvWFJfNBg6Z7IBDpsghbCtCyRIHw2Hb3xyK9rffTmrjf5wQ73hrTt347UKwRK+xa459m14v83B66Z3+33JPvlDcxuupPc9jG51ebhV4vjlXefW+xGhf", + "debug_symbols": "nZdNbuMwDIXvorUXokSJUq5SFIWbuoUBwwncZIBBkbsPGf20HcBZcJPvJRafKImm4y/zNr1eP17m9f30aQ5PX+Z1m5dl/nhZTsfxMp9W/vXLWPmAaA5uMEAFqSCbgx+MswVQ4Ap8ARaEAnYJDCrgcBqMtwUcnhiugGfIg0H+ESyTbQCYHAk8M/JlYEPMhcFWQqWMR6aM56mCjI/MXBhtJVTyrMDTRs4aeN6IlaEyVoofJxtlAzifmAvJVkKlq/SVWMl+jvOnWJjkOuebsFJ+57wTFWbx4/yzq5TxnG/GylAZKyWO88upMheCtU2IUxLhmxCvLCI0EZugJtjPWxG5CrBNQBNy4iACmwhNxCbERyrnXjq8YLiXC4qQ8CBCBkcRPLun220wrR5fLts0STn+KFAu2/O4TevFHNbrsgzmz7hc74M+z+N652Xc+CrnOK1vTDZ8n5dJ1G34jrb7obJP91j8Dg6/o2E/mteYazyvMu45PJg/+BofsiLaRazhjnAvHh/kjxha/hg0+XNpueZgaXcNcd8Bndym5QwckMbB+7YNLIPGIWA7RwzBKhyChbaTLKPKAV13QK9x8Imag8+qHNC1swjoUeVA2B1IcxYhxZ5DUjrkfhbZelVVp35fcFnvdgbatyCy7TiJXNBYRIitO0RIoFkHgO/rwF0H98AieupJ+P0m89ACc+uykUtbZUHfW0HJayzIxnZ3kE1JZQHQipvAWZ2FT90iBJ1FPxGCrMvC526B+93qoQVi306MqLNI/RbBnFX1HajXdwRNryDb+xVZVbehXleBdP3Kuf4vwDlV13Wp90yXNQ5I1J+AlDRPQMwIzSH/9wx95m/jcd5+vX7cxGubx9dlql/fr+vxx9XL33O70l5fztvpOL1dt0mcfrzD8OcT8H9V8OH5JvP9Aw==", "file_map": { "50": { - "source": "fn main(mut x: Field) {\n add1(&mut x);\n assert(x == 3);\n let mut s = S { y: x };\n s.add2();\n assert(s.y == 5);\n // Regression for #1946: Method resolution error when calling &mut methods with a variable of type &mut T\n let s_ref = &mut s;\n s_ref.add2();\n assert(s.y == 7);\n // Test that normal mutable variables are still copied\n let mut a = 0;\n mutate_copy(a);\n assert(a == 0);\n // Test something 3 allocations deep\n let mut nested_allocations = Nested { y: &mut &mut 0 };\n add1(*nested_allocations.y);\n assert(**nested_allocations.y == 1);\n // Test nested struct allocations with a mutable reference to an array.\n let mut c = C { foo: 0, bar: &mut C2 { array: &mut [1, 2] } };\n *c.bar.array = [3, 4];\n assert(*c.bar.array == [3, 4]);\n regression_1887();\n regression_2054();\n regression_2030();\n regression_2255();\n regression_6443();\n assert(x == 3);\n regression_2218_if_inner_if(x, 10);\n regression_2218_if_inner_else(20, x);\n regression_2218_else(x, 3);\n regression_2218_loop(x, 10);\n regression_2560(s_ref);\n}\n\nfn add1(x: &mut Field) {\n *x += 1;\n}\n\nstruct S {\n y: Field,\n}\n\nstruct Nested {\n y: &mut &mut Field,\n}\n\nstruct C {\n foo: Field,\n bar: &mut C2,\n}\n\nstruct C2 {\n array: &mut [Field; 2],\n}\n\nimpl S {\n fn add2(&mut self) {\n self.y += 2;\n }\n\n fn get_y(self) -> Field {\n self.y\n }\n}\n\nfn mutate_copy(mut a: Field) {\n a = 7;\n}\n// Previously the `foo.bar` in `foo.bar.mutate()` would insert an automatic dereference\n// of `foo` which caused the method to wrongly be mutating a copy of bar rather than the original.\nfn regression_1887() {\n let foo = &mut Foo { bar: Bar { x: 0 } };\n foo.bar.mutate();\n assert(foo.bar.x == 32);\n}\n\nstruct Foo {\n bar: Bar,\n}\nstruct Bar {\n x: Field,\n}\n\nimpl Bar {\n fn mutate(&mut self) {\n self.x = 32;\n }\n}\n// Ensure that mutating a variable does not also mutate its copy\nfn regression_2054() {\n let mut x = 2;\n let z = x;\n\n x += 1;\n assert(z == 2);\n}\n// The compiler was still trying to convert an LValue from an array of structs to struct of arrays indexing,\n// even though this conversion was mostly removed elsewhere.\nfn regression_2030() {\n let ref = &mut 0;\n let mut array = [ref, ref];\n let _ = *array[0];\n *array[0] = 1;\n}\n\n// The `mut x: &mut ...` caught a bug handling lvalues where a double-dereference would occur internally\n// in one step rather than being tracked by two separate steps. This lead to assigning the 1 value to the\n// incorrect outer `mut` reference rather than the correct `&mut` reference.\nfn regression_2255() {\n let x = &mut 0;\n regression_2255_helper(x);\n assert(*x == 1);\n}\n\nfn regression_2255_helper(mut x: &mut Field) {\n *x = 1;\n}\n\n// Similar to `regression_2255` but without the double-dereferencing.\n// The test checks that `mem2reg` does not eliminate storing to a reference passed as a parameter.\nfn regression_6443() {\n let x = &mut 0;\n regression_6443_helper(x);\n assert(*x == 1);\n}\n\nfn regression_6443_helper(x: &mut Field) {\n *x = 1;\n}\n\nfn regression_2218(x: Field, y: Field) -> Field {\n let q = &mut &mut 0;\n let q1 = *q;\n let q2 = *q;\n\n if x != y {\n *q1 = 1;\n // Make sure that we correct load reference aliases through multiple blocks\n if x != 20 {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n } else {\n *q2 = 15;\n assert(*q1 == 15);\n }\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n // Have to assign value to return it\n let value = *q1;\n value\n}\n\nfn regression_2218_if_inner_if(x: Field, y: Field) {\n let value = regression_2218(x, y);\n assert(value == 2);\n}\n\nfn regression_2218_if_inner_else(x: Field, y: Field) {\n let value = regression_2218(x, y);\n assert(value == 15);\n}\n\nfn regression_2218_else(x: Field, y: Field) {\n let value = regression_2218(x, y);\n assert(value == 20);\n}\n\nfn regression_2218_loop(x: Field, y: Field) {\n let q = &mut &mut 0;\n let q1 = *q;\n let q2 = *q;\n\n for _ in 0..1 {\n if x != y {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n }\n assert(*q1 == 2);\n\n for _ in 0..1 {\n for _ in 0..5 {\n if x != y {\n *q1 = 1;\n // Make sure that we correct load reference aliases through multiple blocks\n if x != 20 {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n }\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n }\n if x != y {\n *q1 = 1;\n for _ in 0..5 {\n // Make sure that we correct load reference aliases through multiple blocks\n if x != 20 {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n }\n }\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n }\n assert(*q1 == 2);\n\n if x != y {\n for _ in 0..5 {\n if x != y {\n *q1 = 1;\n // Make sure that we correct load reference aliases through multiple blocks\n if x != 20 {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n }\n }\n }\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n assert(*q1 == 2);\n}\n// This is more a feature test than a proper regression.\n// Before, we never automatically dereferenced objects in method calls to their value types.\n// Now, we insert as many `*` as necessary to get to `S`.\nfn regression_2560(s_ref: &mut S) {\n assert(s_ref.get_y() == 7);\n}\n", + "source": "fn main(mut x: Field) {\n add1(&mut x);\n assert(x == 3);\n let mut s = S { y: x };\n s.add2();\n assert(s.y == 5);\n // Regression for #1946: Method resolution error when calling &mut methods with a variable of type &mut T\n let s_ref = &mut s;\n s_ref.add2();\n assert(s.y == 7);\n // Test that normal mutable variables are still copied\n let mut a = 0;\n mutate_copy(a);\n assert(a == 0);\n // Test something 3 allocations deep\n let mut nested_allocations = Nested { y: &mut &mut 0 };\n add1(*nested_allocations.y);\n assert(**nested_allocations.y == 1);\n // Test nested struct allocations with a mutable reference to an array.\n let mut c = C { foo: 0, bar: &mut C2 { array: &mut [1, 2] } };\n *c.bar.array = [3, 4];\n assert(*c.bar.array == [3, 4]);\n regression_1887();\n regression_2054();\n regression_2030();\n regression_2255();\n regression_6443();\n assert(x == 3);\n regression_2218_if_inner_if(x, 10);\n regression_2218_if_inner_else(20, x);\n regression_2218_else(x, 3);\n regression_2218_loop(x, 10);\n regression_2560(s_ref);\n nested_struct_aliases(x, 10);\n assert_eq(x, 3);\n nested_struct_aliases(x, 3);\n}\n\nfn add1(x: &mut Field) {\n *x += 1;\n}\n\nstruct S {\n y: Field,\n}\n\nstruct Nested {\n y: &mut &mut Field,\n}\n\nstruct C {\n foo: Field,\n bar: &mut C2,\n}\n\nstruct C2 {\n array: &mut [Field; 2],\n}\n\nimpl S {\n fn add2(&mut self) {\n self.y += 2;\n }\n\n fn get_y(self) -> Field {\n self.y\n }\n}\n\nfn mutate_copy(mut a: Field) {\n a = 7;\n}\n// Previously the `foo.bar` in `foo.bar.mutate()` would insert an automatic dereference\n// of `foo` which caused the method to wrongly be mutating a copy of bar rather than the original.\nfn regression_1887() {\n let foo = &mut Foo { bar: Bar { x: 0 } };\n foo.bar.mutate();\n assert(foo.bar.x == 32);\n}\n\nstruct Foo {\n bar: Bar,\n}\nstruct Bar {\n x: Field,\n}\n\nimpl Bar {\n fn mutate(&mut self) {\n self.x = 32;\n }\n}\n// Ensure that mutating a variable does not also mutate its copy\nfn regression_2054() {\n let mut x = 2;\n let z = x;\n\n x += 1;\n assert(z == 2);\n}\n// The compiler was still trying to convert an LValue from an array of structs to struct of arrays indexing,\n// even though this conversion was mostly removed elsewhere.\nfn regression_2030() {\n let ref = &mut 0;\n let mut array = [ref, ref];\n let _ = *array[0];\n *array[0] = 1;\n}\n\n// The `mut x: &mut ...` caught a bug handling lvalues where a double-dereference would occur internally\n// in one step rather than being tracked by two separate steps. This lead to assigning the 1 value to the\n// incorrect outer `mut` reference rather than the correct `&mut` reference.\nfn regression_2255() {\n let x = &mut 0;\n regression_2255_helper(x);\n assert(*x == 1);\n}\n\nfn regression_2255_helper(mut x: &mut Field) {\n *x = 1;\n}\n\n// Similar to `regression_2255` but without the double-dereferencing.\n// The test checks that `mem2reg` does not eliminate storing to a reference passed as a parameter.\nfn regression_6443() {\n let x = &mut 0;\n regression_6443_helper(x);\n assert(*x == 1);\n}\n\nfn regression_6443_helper(x: &mut Field) {\n *x = 1;\n}\n\nfn regression_2218(x: Field, y: Field) -> Field {\n let q = &mut &mut 0;\n let q1 = *q;\n let q2 = *q;\n\n if x != y {\n *q1 = 1;\n // Make sure that we correct load reference aliases through multiple blocks\n if x != 20 {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n } else {\n *q2 = 15;\n assert(*q1 == 15);\n }\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n // Have to assign value to return it\n let value = *q1;\n value\n}\n\nfn regression_2218_if_inner_if(x: Field, y: Field) {\n let value = regression_2218(x, y);\n assert(value == 2);\n}\n\nfn regression_2218_if_inner_else(x: Field, y: Field) {\n let value = regression_2218(x, y);\n assert(value == 15);\n}\n\nfn regression_2218_else(x: Field, y: Field) {\n let value = regression_2218(x, y);\n assert(value == 20);\n}\n\nfn regression_2218_loop(x: Field, y: Field) {\n let q = &mut &mut 0;\n let q1 = *q;\n let q2 = *q;\n\n for _ in 0..1 {\n if x != y {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n }\n assert(*q1 == 2);\n\n for _ in 0..1 {\n for _ in 0..5 {\n if x != y {\n *q1 = 1;\n // Make sure that we correct load reference aliases through multiple blocks\n if x != 20 {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n }\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n }\n if x != y {\n *q1 = 1;\n for _ in 0..5 {\n // Make sure that we correct load reference aliases through multiple blocks\n if x != 20 {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n }\n }\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n }\n assert(*q1 == 2);\n\n if x != y {\n for _ in 0..5 {\n if x != y {\n *q1 = 1;\n // Make sure that we correct load reference aliases through multiple blocks\n if x != 20 {\n *q1 = 10;\n *q2 = 2; // now we'd expect q1 == q2 == 2\n assert(*q1 == 2);\n }\n }\n }\n } else {\n *q2 = 20;\n assert(*q1 == 20);\n }\n assert(*q1 == 2);\n}\n// This is more a feature test than a proper regression.\n// Before, we never automatically dereferenced objects in method calls to their value types.\n// Now, we insert as many `*` as necessary to get to `S`.\nfn regression_2560(s_ref: &mut S) {\n assert(s_ref.get_y() == 7);\n}\n\nstruct MyStruct {\n a: Field,\n b: u32,\n}\n\nstruct Outer {\n inner: MyStruct,\n}\n\nfn nested_struct_aliases(x: Field, y: Field) {\n let mut var = Outer { inner: MyStruct { a: 0, b: 0 } };\n let ref_outer = &mut var;\n let ref_inner1 = &mut ref_outer.inner;\n let ref_inner2 = &mut var.inner;\n\n if x != y {\n (*ref_inner1).a = 5;\n (*ref_inner1).b = 7;\n (*ref_inner2).a = 3;\n (*ref_inner2).b = 10;\n\n for _ in 0..3 {\n (*ref_inner1).a += 1;\n (*ref_inner1).b += 2;\n (*ref_inner2).a += 2;\n (*ref_inner2).b += 4;\n }\n } else {\n (*ref_inner2).a = 20;\n (*ref_inner2).b = 15;\n (*ref_inner1).a = 25;\n (*ref_inner1).b = 30;\n\n for _ in 0..3 {\n (*ref_inner2).a += 5;\n (*ref_inner2).b += 3;\n (*ref_inner1).a += 4;\n (*ref_inner1).b += 10;\n }\n }\n\n if x != y {\n assert(var.inner.a == 12);\n assert(var.inner.b == 28);\n assert(ref_inner1.a == 12);\n assert(ref_inner1.b == 28);\n assert(ref_inner2.a == 12);\n assert(ref_inner2.b == 28);\n assert(ref_outer.inner.a == 12);\n assert(ref_outer.inner.b == 28);\n } else {\n assert(var.inner.a == 52);\n assert(var.inner.b == 69);\n assert(ref_inner1.a == 52);\n assert(ref_inner1.b == 69);\n assert(ref_inner2.a == 52);\n assert(ref_inner2.b == 69);\n assert(ref_outer.inner.a == 52);\n assert(ref_outer.inner.b == 69);\n }\n}\n", "path": "" } },