//! > Test nopanic function cycle.

//! > test_runner_name
test_function_lowering(expect_diagnostics: true)

//! > function
fn foo(x: felt252) nopanic {
    foo(x);
}

//! > function_name
foo

//! > module_code

//! > semantic_diagnostics

//! > lowering_diagnostics
error: Call cycle of `nopanic` functions is not allowed.
 --> lib.cairo:1:1
fn foo(x: felt252) nopanic {
^**************************^

//! > lowering_flat
Parameters: v0: core::RangeCheck, v1: core::gas::GasBuiltin, v2: core::felt252
blk0 (root):
Statements:
End:
  Match(match core::gas::withdraw_gas(v0, v1) {
    Option::Some(v3, v4) => blk1,
    Option::None(v5, v6) => blk2,
  })

blk1:
Statements:
  (v7: core::RangeCheck, v8: core::gas::GasBuiltin, v9: core::panics::PanicResult::<((),)>) <- test::foo(v3, v4, v2)
End:
  Return(v7, v8, v9)

blk2:
Statements:
  (v10: core::array::Array::<core::felt252>) <- core::array::array_new::<core::felt252>()
  (v11: core::felt252) <- 375233589013918064796019
  (v12: core::array::Array::<core::felt252>) <- core::array::array_append::<core::felt252>(v10, v11)
  (v13: core::panics::Panic) <- struct_construct()
  (v14: (core::panics::Panic, core::array::Array::<core::felt252>)) <- struct_construct(v13, v12)
  (v15: core::panics::PanicResult::<((),)>) <- PanicResult::Err(v14)
End:
  Return(v5, v6, v15)

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

//! > Test explicit gas handling.

//! > test_runner_name
test_function_lowering(expect_diagnostics: false)

//! > function
fn foo(x: felt252) {
    match core::gas::withdraw_gas() {
        Option::Some(_) => foo(x),
        Option::None => {}
    }
}

//! > function_name
foo

//! > module_code

//! > semantic_diagnostics

//! > lowering_diagnostics

//! > lowering_flat
Parameters: v0: core::RangeCheck, v1: core::gas::GasBuiltin, v2: core::felt252
blk0 (root):
Statements:
End:
  Match(match core::gas::withdraw_gas(v0, v1) {
    Option::Some(v3, v4) => blk1,
    Option::None(v5, v6) => blk2,
  })

blk1:
Statements:
  (v7: core::RangeCheck, v8: core::gas::GasBuiltin) <- test::foo(v3, v4, v2)
End:
  Return(v7, v8)

blk2:
Statements:
End:
  Return(v5, v6)

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

//! > Test nopanic function cycle with withdraw gas.

//! > test_runner_name
test_function_lowering(expect_diagnostics: false)

//! > function
fn foo(x: felt252, costs: core::gas::BuiltinCosts) nopanic {
    match core::gas::withdraw_gas_all(costs) {
        Option::Some(_) => foo(x, costs),
        Option::None => {}
    }
}

//! > function_name
foo

//! > module_code

//! > semantic_diagnostics

//! > lowering_diagnostics

//! > lowering_flat
Parameters: v0: core::RangeCheck, v1: core::gas::GasBuiltin, v2: core::felt252, v3: core::gas::BuiltinCosts
blk0 (root):
Statements:
End:
  Match(match core::gas::withdraw_gas_all(v0, v1, v3) {
    Option::Some(v4, v5) => blk1,
    Option::None(v6, v7) => blk2,
  })

blk1:
Statements:
  (v8: core::RangeCheck, v9: core::gas::GasBuiltin) <- test::foo(v4, v5, v2, v3)
End:
  Return(v8, v9)

blk2:
Statements:
End:
  Return(v6, v7)

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

//! > Test destructor basic cycle.

//! > test_runner_name
test_function_lowering(expect_diagnostics: true)

//! > function
fn foo() {}

//! > function_name
foo

//! > module_code
struct A {}
impl ADestruct of Destruct<A> {
    fn destruct(self: A) nopanic {
        let A { } = self;
        B {};
    }
}

struct B {}
impl BDestruct of Destruct<B> {
    fn destruct(self: B) nopanic {
        let B { } = self;
        A {};
    }
}

//! > semantic_diagnostics

//! > lowering_diagnostics
error: Call cycle of `nopanic` functions is not allowed.
 --> lib.cairo:3:5
    fn destruct(self: A) nopanic {
    ^****************************^

error: Call cycle of `nopanic` functions is not allowed.
 --> lib.cairo:11:5
    fn destruct(self: B) nopanic {
    ^****************************^

//! > lowering_flat
Parameters:
blk0 (root):
Statements:
End:
  Return()
