//! > Test struct folding.

//! > test_runner_name
test_cancel_ops

//! > function
fn foo(a: felt252) -> felt252 {
   let b = (a,);
   let c = (b,);
   let (d,)  = c;
   let (e,)  = d;
   e
}

//! > function_name
foo

//! > module_code

//! > semantic_diagnostics

//! > lowering_diagnostics

//! > before
Parameters: v0: core::felt252
blk0 (root):
Statements:
  (v1: (core::felt252,)) <- struct_construct(v0)
  (v2: ((core::felt252,),)) <- struct_construct(v1)
  (v3: (core::felt252,)) <- struct_destructure(v2)
  (v4: core::felt252) <- struct_destructure(v3)
End:
  Return(v4)

//! > after
Parameters: v0: core::felt252
blk0 (root):
Statements:
End:
  Return(v0)

//! > ==========================================================================

//! > Test destruct folding.

//! > test_runner_name
test_cancel_ops

//! > function
fn foo(a: ((felt252, ), )) -> ((felt252, ), ) {
   let (b, ) = a;
   let (c, ) = b;
   ((c,),)
}

//! > function_name
foo

//! > module_code

//! > semantic_diagnostics

//! > lowering_diagnostics

//! > before
Parameters: v0: ((core::felt252,),)
blk0 (root):
Statements:
  (v1: (core::felt252,)) <- struct_destructure(v0)
  (v2: core::felt252) <- struct_destructure(v1)
  (v3: (core::felt252,)) <- struct_construct(v2)
  (v4: ((core::felt252,),)) <- struct_construct(v3)
End:
  Return(v4)

//! > after
Parameters: v0: ((core::felt252,),)
blk0 (root):
Statements:
End:
  Return(v0)

//! > ==========================================================================

//! > Test destruct after merge (optimization not possible).

//! > test_runner_name
test_cancel_ops

//! > function
fn foo(a: felt252) -> felt252 {
   let (b,) = match a {
      0 => (0,),
      _ => (a,),
   };
   b
}

//! > function_name
foo

//! > module_code

//! > semantic_diagnostics

//! > lowering_diagnostics

//! > before
Parameters: v0: core::felt252
blk0 (root):
Statements:
End:
  Match(match core::felt252_is_zero(v0) {
    IsZeroResult::Zero => blk1,
    IsZeroResult::NonZero(v1) => blk2,
  })

blk1:
Statements:
  (v2: core::felt252) <- 0u
  (v3: (core::felt252,)) <- struct_construct(v2)
End:
  Goto(blk3, {v3 -> v5})

blk2:
Statements:
  (v4: (core::felt252,)) <- struct_construct(v0)
End:
  Goto(blk3, {v4 -> v5})

blk3:
Statements:
  (v6: core::felt252) <- struct_destructure(v5)
End:
  Return(v6)

//! > after
Parameters: v0: core::felt252
blk0 (root):
Statements:
End:
  Match(match core::felt252_is_zero(v0) {
    IsZeroResult::Zero => blk1,
    IsZeroResult::NonZero(v1) => blk2,
  })

blk1:
Statements:
  (v2: core::felt252) <- 0u
  (v3: (core::felt252,)) <- struct_construct(v2)
End:
  Goto(blk3, {v3 -> v5})

blk2:
Statements:
  (v4: (core::felt252,)) <- struct_construct(v0)
End:
  Goto(blk3, {v4 -> v5})

blk3:
Statements:
  (v6: core::felt252) <- struct_destructure(v5)
End:
  Return(v6)

//! > ==========================================================================

//! > Test use in one arm (optimization not possible)

//! > test_runner_name
test_cancel_ops

//! > function
fn foo(a: felt252) -> felt252 {
   let arr = array![10, 11, 12];

   let c = (a, arr);
   if a == 0 {
     let (a, _arr) = c;
     return a;
   } else {
      cosume(c);
      return 1;
   }
}

//! > function_name
foo

//! > module_code
extern fn cosume(arg: (felt252, Array<felt252>)) nopanic;

//! > semantic_diagnostics

//! > lowering_diagnostics

//! > before
Parameters: v0: core::felt252
blk0 (root):
Statements:
  (v16: core::array::Array::<core::felt252>) <- core::array::array_new::<core::felt252>()
  (v2: core::felt252) <- 10u
  (v17: core::array::Array::<core::felt252>) <- core::array::array_append::<core::felt252>(v16, v2)
  (v5: core::felt252) <- 11u
  (v19: core::array::Array::<core::felt252>) <- core::array::array_append::<core::felt252>(v17, v5)
  (v8: core::felt252) <- 12u
  (v21: core::array::Array::<core::felt252>) <- core::array::array_append::<core::felt252>(v19, v8)
  (v11: (core::felt252, core::array::Array::<core::felt252>)) <- struct_construct(v0, v21)
End:
  Match(match core::felt252_is_zero(v0) {
    IsZeroResult::Zero => blk1,
    IsZeroResult::NonZero(v14) => blk2,
  })

blk1:
Statements:
  (v12: core::felt252, v13: core::array::Array::<core::felt252>) <- struct_destructure(v11)
End:
  Return(v12)

blk2:
Statements:
  () <- test::cosume(v11)
  (v15: core::felt252) <- 1u
End:
  Return(v15)

//! > after
Parameters: v0: core::felt252
blk0 (root):
Statements:
  (v16: core::array::Array::<core::felt252>) <- core::array::array_new::<core::felt252>()
  (v2: core::felt252) <- 10u
  (v17: core::array::Array::<core::felt252>) <- core::array::array_append::<core::felt252>(v16, v2)
  (v5: core::felt252) <- 11u
  (v19: core::array::Array::<core::felt252>) <- core::array::array_append::<core::felt252>(v17, v5)
  (v8: core::felt252) <- 12u
  (v21: core::array::Array::<core::felt252>) <- core::array::array_append::<core::felt252>(v19, v8)
  (v11: (core::felt252, core::array::Array::<core::felt252>)) <- struct_construct(v0, v21)
End:
  Match(match core::felt252_is_zero(v0) {
    IsZeroResult::Zero => blk1,
    IsZeroResult::NonZero(v14) => blk2,
  })

blk1:
Statements:
  (v12: core::felt252, v13: core::array::Array::<core::felt252>) <- struct_destructure(v11)
End:
  Return(v12)

blk2:
Statements:
  () <- test::cosume(v11)
  (v15: core::felt252) <- 1u
End:
  Return(v15)

//! > ==========================================================================

//! > Test snap/desnap

//! > test_runner_name
test_cancel_ops

//! > function
fn foo(a: felt252) -> felt252 {
   let snap = @a;
   let desnap = *snap;
   let snap_desnap = @desnap;
   *snap + *snap_desnap
}

//! > function_name
foo

//! > module_code

//! > semantic_diagnostics

//! > lowering_diagnostics

//! > before
Parameters: v0: core::felt252
blk0 (root):
Statements:
  (v1: core::felt252, v2: @core::felt252) <- snapshot(v0)
  (v3: core::felt252) <- desnap(v2)
  (v4: core::felt252, v5: @core::felt252) <- snapshot(v3)
  (v6: core::felt252) <- desnap(v2)
  (v7: core::felt252) <- desnap(v5)
  (v9: core::felt252) <- core::felt252_add(v6, v7)
End:
  Return(v9)

//! > after
Parameters: v0: core::felt252
blk0 (root):
Statements:
  (v9: core::felt252) <- core::felt252_add(v0, v0)
End:
  Return(v9)

//! > ==========================================================================

//! > Test remove panic generated destructure construct pair.

//! > test_runner_name
test_cancel_ops

//! > function
fn foo(a: u32) -> u32 {
  a + a
}

//! > function_name
foo

//! > module_code

//! > semantic_diagnostics

//! > lowering_diagnostics

//! > before
Parameters: v0: core::integer::u32
blk0 (root):
Statements:
  (v2: core::panics::PanicResult::<(core::integer::u32,)>) <- core::integer::U32Add::add(v0, v0)
End:
  Match(match_enum(v2) {
    PanicResult::Ok(v3) => blk1,
    PanicResult::Err(v5) => blk2,
  })

blk1:
Statements:
  (v4: core::integer::u32) <- struct_destructure(v3)
  (v6: (core::integer::u32,)) <- struct_construct(v4)
  (v7: core::panics::PanicResult::<(core::integer::u32,)>) <- PanicResult::Ok(v6)
End:
  Return(v7)

blk2:
Statements:
  (v8: core::panics::PanicResult::<(core::integer::u32,)>) <- PanicResult::Err(v5)
End:
  Return(v8)

//! > after
Parameters: v0: core::integer::u32
blk0 (root):
Statements:
  (v2: core::panics::PanicResult::<(core::integer::u32,)>) <- core::integer::U32Add::add(v0, v0)
End:
  Match(match_enum(v2) {
    PanicResult::Ok(v3) => blk1,
    PanicResult::Err(v5) => blk2,
  })

blk1:
Statements:
  (v7: core::panics::PanicResult::<(core::integer::u32,)>) <- PanicResult::Ok(v3)
End:
  Return(v7)

blk2:
Statements:
  (v8: core::panics::PanicResult::<(core::integer::u32,)>) <- PanicResult::Err(v5)
End:
  Return(v8)

//! > ==========================================================================

//! > Test destructure + construct to different type (optimization not possible).

//! > test_runner_name
test_cancel_ops

//! > function
fn foo(a: (u32,) ) -> MyStruct {
  let (b, ) = a;
  MyStruct { b }
}

//! > function_name
foo

//! > module_code
struct MyStruct {
  b: u32,
}

//! > semantic_diagnostics

//! > lowering_diagnostics

//! > before
Parameters: v0: (core::integer::u32,)
blk0 (root):
Statements:
  (v1: core::integer::u32) <- struct_destructure(v0)
  (v2: test::MyStruct) <- struct_construct(v1)
End:
  Return(v2)

//! > after
Parameters: v0: (core::integer::u32,)
blk0 (root):
Statements:
  (v1: core::integer::u32) <- struct_destructure(v0)
  (v2: test::MyStruct) <- struct_construct(v1)
End:
  Return(v2)

//! > ==========================================================================

//! > destracture remapped to snapshot.

//! > test_runner_name
test_cancel_ops

//! > function
fn foo(a: (u32,), b: felt252) -> u32 {
  let d = @if b == 0 {
    let (c, ) = a;
    c
  } else {
    let (c, ) = a;
    c
  };

  *d
}

//! > function_name
foo

//! > module_code

//! > semantic_diagnostics

//! > lowering_diagnostics

//! > before
Parameters: v0: (core::integer::u32,), v1: core::felt252
blk0 (root):
Statements:
End:
  Match(match core::felt252_is_zero(v1) {
    IsZeroResult::Zero => blk1,
    IsZeroResult::NonZero(v3) => blk2,
  })

blk1:
Statements:
  (v2: core::integer::u32) <- struct_destructure(v0)
End:
  Goto(blk3, {v2 -> v5})

blk2:
Statements:
  (v4: core::integer::u32) <- struct_destructure(v0)
End:
  Goto(blk3, {v4 -> v5})

blk3:
Statements:
  (v6: core::integer::u32, v7: @core::integer::u32) <- snapshot(v5)
  (v8: core::integer::u32) <- desnap(v7)
End:
  Return(v8)

//! > after
Parameters: v0: (core::integer::u32,), v1: core::felt252
blk0 (root):
Statements:
End:
  Match(match core::felt252_is_zero(v1) {
    IsZeroResult::Zero => blk1,
    IsZeroResult::NonZero(v3) => blk2,
  })

blk1:
Statements:
  (v2: core::integer::u32) <- struct_destructure(v0)
End:
  Goto(blk3, {v2 -> v5})

blk2:
Statements:
  (v4: core::integer::u32) <- struct_destructure(v0)
End:
  Goto(blk3, {v4 -> v5})

blk3:
Statements:
End:
  Return(v5)
