//! > 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) <- 0
  (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) <- 0
  (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:
  (v23: core::array::Array::<core::felt252>) <- core::array::array_new::<core::felt252>()
  (v2: core::felt252) <- 10
  (v24: core::array::Array::<core::felt252>) <- core::array::array_append::<core::felt252>(v23, v2)
  (v5: core::felt252) <- 11
  (v25: core::array::Array::<core::felt252>) <- core::array::array_append::<core::felt252>(v24, v5)
  (v8: core::felt252) <- 12
  (v26: core::array::Array::<core::felt252>) <- core::array::array_append::<core::felt252>(v25, v8)
  (v11: (core::felt252, core::array::Array::<core::felt252>)) <- struct_construct(v0, v26)
  (v12: core::felt252, v13: @core::felt252) <- snapshot(v0)
  (v14: core::felt252) <- 0
  (v15: core::felt252, v16: @core::felt252) <- snapshot(v14)
  (v27: core::felt252) <- desnap(v13)
  (v28: core::felt252) <- desnap(v16)
  (v29: core::felt252) <- core::felt252_sub(v27, v28)
End:
  Match(match core::felt252_is_zero(v29) {
    IsZeroResult::Zero => blk1,
    IsZeroResult::NonZero(v30) => blk2,
  })

blk1:
Statements:
  (v31: ()) <- struct_construct()
  (v32: core::bool) <- bool::True(v31)
End:
  Goto(blk3, {v32 -> v17})

blk2:
Statements:
  (v33: ()) <- struct_construct()
  (v34: core::bool) <- bool::False(v33)
End:
  Goto(blk3, {v34 -> v17})

blk3:
Statements:
End:
  Match(match_enum(v17) {
    bool::False(v21) => blk4,
    bool::True(v18) => blk5,
  })

blk4:
Statements:
  () <- test::cosume(v11)
  (v22: core::felt252) <- 1
End:
  Return(v22)

blk5:
Statements:
  (v19: core::felt252, v20: core::array::Array::<core::felt252>) <- struct_destructure(v11)
End:
  Return(v19)

//! > after
Parameters: v0: core::felt252
blk0 (root):
Statements:
  (v23: core::array::Array::<core::felt252>) <- core::array::array_new::<core::felt252>()
  (v2: core::felt252) <- 10
  (v24: core::array::Array::<core::felt252>) <- core::array::array_append::<core::felt252>(v23, v2)
  (v5: core::felt252) <- 11
  (v25: core::array::Array::<core::felt252>) <- core::array::array_append::<core::felt252>(v24, v5)
  (v8: core::felt252) <- 12
  (v26: core::array::Array::<core::felt252>) <- core::array::array_append::<core::felt252>(v25, v8)
  (v11: (core::felt252, core::array::Array::<core::felt252>)) <- struct_construct(v0, v26)
  (v14: core::felt252) <- 0
  (v29: core::felt252) <- core::felt252_sub(v0, v14)
End:
  Match(match core::felt252_is_zero(v29) {
    IsZeroResult::Zero => blk1,
    IsZeroResult::NonZero(v30) => blk2,
  })

blk1:
Statements:
  (v31: ()) <- struct_construct()
  (v32: core::bool) <- bool::True(v31)
End:
  Goto(blk3, {v32 -> v17})

blk2:
Statements:
  (v33: ()) <- struct_construct()
  (v34: core::bool) <- bool::False(v33)
End:
  Goto(blk3, {v34 -> v17})

blk3:
Statements:
End:
  Match(match_enum(v17) {
    bool::False(v21) => blk4,
    bool::True(v18) => blk5,
  })

blk4:
Statements:
  () <- test::cosume(v11)
  (v22: core::felt252) <- 1
End:
  Return(v22)

blk5:
Statements:
  (v19: core::felt252, v20: core::array::Array::<core::felt252>) <- struct_destructure(v11)
End:
  Return(v19)

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

//! > 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:
End:
  Match(match core::integer::u32_overflowing_add(v0, v0) {
    Result::Ok(v9) => blk1,
    Result::Err(v10) => blk2,
  })

blk1:
Statements:
  (v11: (core::integer::u32,)) <- struct_construct(v9)
  (v12: core::panics::PanicResult::<(core::integer::u32,)>) <- PanicResult::Ok(v11)
End:
  Goto(blk3, {v12 -> v2})

blk2:
Statements:
  (v13: core::array::Array::<core::felt252>) <- core::array::array_new::<core::felt252>()
  (v14: core::felt252) <- 155785504323917466144735657540098748279
  (v15: core::array::Array::<core::felt252>) <- core::array::array_append::<core::felt252>(v13, v14)
  (v16: core::panics::Panic) <- struct_construct()
  (v17: (core::panics::Panic, core::array::Array::<core::felt252>)) <- struct_construct(v16, v15)
  (v18: core::panics::PanicResult::<(core::integer::u32,)>) <- PanicResult::Err(v17)
End:
  Goto(blk3, {v18 -> v2})

blk3:
Statements:
End:
  Match(match_enum(v2) {
    PanicResult::Ok(v3) => blk4,
    PanicResult::Err(v5) => blk5,
  })

blk4:
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)

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

//! > after
Parameters: v0: core::integer::u32
blk0 (root):
Statements:
End:
  Match(match core::integer::u32_overflowing_add(v0, v0) {
    Result::Ok(v9) => blk1,
    Result::Err(v10) => blk2,
  })

blk1:
Statements:
  (v11: (core::integer::u32,)) <- struct_construct(v9)
  (v12: core::panics::PanicResult::<(core::integer::u32,)>) <- PanicResult::Ok(v11)
End:
  Goto(blk3, {v12 -> v2})

blk2:
Statements:
  (v13: core::array::Array::<core::felt252>) <- core::array::array_new::<core::felt252>()
  (v14: core::felt252) <- 155785504323917466144735657540098748279
  (v15: core::array::Array::<core::felt252>) <- core::array::array_append::<core::felt252>(v13, v14)
  (v16: core::panics::Panic) <- struct_construct()
  (v17: (core::panics::Panic, core::array::Array::<core::felt252>)) <- struct_construct(v16, v15)
  (v18: core::panics::PanicResult::<(core::integer::u32,)>) <- PanicResult::Err(v17)
End:
  Goto(blk3, {v18 -> v2})

blk3:
Statements:
End:
  Match(match_enum(v2) {
    PanicResult::Ok(v3) => blk4,
    PanicResult::Err(v5) => blk5,
  })

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

blk5:
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:
  (v2: core::felt252, v3: @core::felt252) <- snapshot(v1)
  (v4: core::felt252) <- 0
  (v5: core::felt252, v6: @core::felt252) <- snapshot(v4)
  (v16: core::felt252) <- desnap(v3)
  (v17: core::felt252) <- desnap(v6)
  (v18: core::felt252) <- core::felt252_sub(v16, v17)
End:
  Match(match core::felt252_is_zero(v18) {
    IsZeroResult::Zero => blk1,
    IsZeroResult::NonZero(v19) => blk2,
  })

blk1:
Statements:
  (v20: ()) <- struct_construct()
  (v21: core::bool) <- bool::True(v20)
End:
  Goto(blk3, {v21 -> v7})

blk2:
Statements:
  (v22: ()) <- struct_construct()
  (v23: core::bool) <- bool::False(v22)
End:
  Goto(blk3, {v23 -> v7})

blk3:
Statements:
End:
  Match(match_enum(v7) {
    bool::False(v10) => blk4,
    bool::True(v8) => blk5,
  })

blk4:
Statements:
  (v11: core::integer::u32) <- struct_destructure(v0)
End:
  Goto(blk6, {v11 -> v12})

blk5:
Statements:
  (v9: core::integer::u32) <- struct_destructure(v0)
End:
  Goto(blk6, {v9 -> v12})

blk6:
Statements:
  (v13: core::integer::u32, v14: @core::integer::u32) <- snapshot(v12)
  (v15: core::integer::u32) <- desnap(v14)
End:
  Return(v15)

//! > after
Parameters: v0: (core::integer::u32,), v1: core::felt252
blk0 (root):
Statements:
  (v4: core::felt252) <- 0
  (v18: core::felt252) <- core::felt252_sub(v1, v4)
End:
  Match(match core::felt252_is_zero(v18) {
    IsZeroResult::Zero => blk1,
    IsZeroResult::NonZero(v19) => blk2,
  })

blk1:
Statements:
  (v20: ()) <- struct_construct()
  (v21: core::bool) <- bool::True(v20)
End:
  Goto(blk3, {v21 -> v7})

blk2:
Statements:
  (v22: ()) <- struct_construct()
  (v23: core::bool) <- bool::False(v22)
End:
  Goto(blk3, {v23 -> v7})

blk3:
Statements:
End:
  Match(match_enum(v7) {
    bool::False(v10) => blk4,
    bool::True(v8) => blk5,
  })

blk4:
Statements:
  (v11: core::integer::u32) <- struct_destructure(v0)
End:
  Goto(blk6, {v11 -> v12})

blk5:
Statements:
  (v9: core::integer::u32) <- struct_destructure(v0)
End:
  Goto(blk6, {v9 -> v12})

blk6:
Statements:
End:
  Return(v12)

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

//! > Test variable renamed twice.

//! > test_runner_name
test_cancel_ops

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

//! > function_name
foo

//! > module_code
extern fn use_tuple(a: (felt252, felt252)) nopanic;

//! > semantic_diagnostics

//! > lowering_diagnostics

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

//! > after
Parameters: v0: (core::felt252, core::felt252)
blk0 (root):
Statements:
  (v1: core::felt252, v2: core::felt252) <- struct_destructure(v0)
  () <- test::use_tuple(v0)
  (v7: (core::felt252, core::felt252)) <- struct_construct(v2, v1)
End:
  Return(v7)
