//! > Test struct folding.

//! > test_runner_name
test_cancel_ops

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

//! > function_name
foo

//! > 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_code
fn foo(a: ((felt252,),)) -> ((felt252,),) {
    let (b,) = a;
    let (c,) = b;
    ((c,),)
}

//! > function_name
foo

//! > 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_code
fn foo(a: felt252) -> felt252 {
    let (b,) = match a {
        0 => (0,),
        _ => (a,),
    };
    b
}

//! > function_name
foo

//! > 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 -> v4})

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

blk3:
Statements:
  (v6: core::felt252) <- struct_destructure(v4)
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 -> v4})

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

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

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

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

//! > test_runner_name
test_cancel_ops

//! > function_code
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 {
        consume(c);
        return 1;
    }
}

//! > function_name
foo

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

//! > semantic_diagnostics

//! > lowering_diagnostics

//! > before
Parameters: v0: core::felt252
blk0 (root):
Statements:
  (v1: core::array::Array::<core::felt252>) <- core::array::array_new::<core::felt252>()
  (v2: core::felt252) <- 10
  (v3: core::array::Array::<core::felt252>) <- core::array::array_append::<core::felt252>(v1, v2)
  (v5: core::felt252) <- 11
  (v6: core::array::Array::<core::felt252>) <- core::array::array_append::<core::felt252>(v3, v5)
  (v8: core::felt252) <- 12
  (v9: core::array::Array::<core::felt252>) <- core::array::array_append::<core::felt252>(v6, v8)
  (v11: (core::felt252, core::array::Array::<core::felt252>)) <- struct_construct(v0, v9)
  (v12: core::felt252, v13: @core::felt252) <- snapshot(v0)
  (v17: core::felt252) <- desnap(v13)
End:
  Match(match core::felt252_is_zero(v17) {
    IsZeroResult::Zero => blk1,
    IsZeroResult::NonZero(v18) => blk2,
  })

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

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

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

blk4:
Statements:
  () <- test::consume(v11)
  (v26: core::felt252) <- 1
End:
  Return(v26)

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

//! > after
Parameters: v0: core::felt252
blk0 (root):
Statements:
  (v1: core::array::Array::<core::felt252>) <- core::array::array_new::<core::felt252>()
  (v2: core::felt252) <- 10
  (v3: core::array::Array::<core::felt252>) <- core::array::array_append::<core::felt252>(v1, v2)
  (v5: core::felt252) <- 11
  (v6: core::array::Array::<core::felt252>) <- core::array::array_append::<core::felt252>(v3, v5)
  (v8: core::felt252) <- 12
  (v9: core::array::Array::<core::felt252>) <- core::array::array_append::<core::felt252>(v6, v8)
  (v11: (core::felt252, core::array::Array::<core::felt252>)) <- struct_construct(v0, v9)
End:
  Match(match core::felt252_is_zero(v0) {
    IsZeroResult::Zero => blk1,
    IsZeroResult::NonZero(v18) => blk2,
  })

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

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

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

blk4:
Statements:
  () <- test::consume(v11)
  (v26: core::felt252) <- 1
End:
  Return(v26)

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

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

//! > Test snap/desnap

//! > test_runner_name
test_cancel_ops

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

//! > function_name
foo

//! > 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)
  (v8: core::felt252) <- core::felt252_add(v6, v7)
End:
  Return(v8)

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

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

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

//! > test_runner_name
test_cancel_ops

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

//! > function_name
foo

//! > 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(v1) => blk1,
    Result::Err(v2) => blk2,
  })

blk1:
Statements:
  (v3: (core::integer::u32,)) <- struct_construct(v1)
  (v4: core::panics::PanicResult::<(core::integer::u32,)>) <- PanicResult::Ok(v3)
End:
  Goto(blk3, {v4 -> v5})

blk2:
Statements:
  (v6: (core::panics::Panic, core::array::Array::<core::felt252>)) <- core::panic_with_const_felt252::<155785504323917466144735657540098748279>()
  (v7: core::panics::PanicResult::<(core::integer::u32,)>) <- PanicResult::Err(v6)
End:
  Goto(blk3, {v7 -> v5})

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

blk4:
Statements:
  (v10: core::integer::u32) <- struct_destructure(v8)
  (v11: (core::integer::u32,)) <- struct_construct(v10)
  (v12: core::panics::PanicResult::<(core::integer::u32,)>) <- PanicResult::Ok(v11)
End:
  Return(v12)

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

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

blk1:
Statements:
  (v3: (core::integer::u32,)) <- struct_construct(v1)
  (v4: core::panics::PanicResult::<(core::integer::u32,)>) <- PanicResult::Ok(v3)
End:
  Goto(blk3, {v4 -> v5})

blk2:
Statements:
  (v6: (core::panics::Panic, core::array::Array::<core::felt252>)) <- core::panic_with_const_felt252::<155785504323917466144735657540098748279>()
  (v7: core::panics::PanicResult::<(core::integer::u32,)>) <- PanicResult::Err(v6)
End:
  Goto(blk3, {v7 -> v5})

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

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

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

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

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

//! > test_runner_name
test_cancel_ops

//! > function_code
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_code
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

//! > semantic_diagnostics

//! > lowering_diagnostics

//! > before
Parameters: v0: (core::integer::u32,), v1: core::felt252
blk0 (root):
Statements:
  (v2: core::felt252, v3: @core::felt252) <- snapshot(v1)
  (v7: core::felt252) <- desnap(v3)
End:
  Match(match core::felt252_is_zero(v7) {
    IsZeroResult::Zero => blk1,
    IsZeroResult::NonZero(v8) => blk2,
  })

blk1:
Statements:
  (v9: ()) <- struct_construct()
  (v10: core::bool) <- bool::True(v9)
End:
  Goto(blk3, {v10 -> v11})

blk2:
Statements:
  (v12: ()) <- struct_construct()
  (v13: core::bool) <- bool::False(v12)
End:
  Goto(blk3, {v13 -> v11})

blk3:
Statements:
End:
  Match(match_enum(v11) {
    bool::False(v14) => blk4,
    bool::True(v15) => blk5,
  })

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

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

blk6:
Statements:
  (v19: core::integer::u32, v20: @core::integer::u32) <- snapshot(v17)
  (v21: core::integer::u32) <- desnap(v20)
End:
  Return(v21)

//! > 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(v8) => blk2,
  })

blk1:
Statements:
  (v9: ()) <- struct_construct()
  (v10: core::bool) <- bool::True(v9)
End:
  Goto(blk3, {v10 -> v11})

blk2:
Statements:
  (v12: ()) <- struct_construct()
  (v13: core::bool) <- bool::False(v12)
End:
  Goto(blk3, {v13 -> v11})

blk3:
Statements:
End:
  Match(match_enum(v11) {
    bool::False(v14) => blk4,
    bool::True(v15) => blk5,
  })

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

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

blk6:
Statements:
End:
  Return(v17)

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

//! > Test variable renamed twice.

//! > test_runner_name
test_cancel_ops

//! > function_code
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)
