//! > Test simple inlining.

//! > test_runner_name
test_function_inlining

//! > function
fn foo(n: felt252) -> felt252 {
  -n
}

//! > function_name
foo

//! > module_code

//! > semantic_diagnostics

//! > before
Parameters: v0: core::felt252
blk0 (root):
Statements:
  (v1: core::felt252) <- core::Felt252Neg::neg(v0)
End:
  Return(v1)

//! > after
Parameters: v0: core::felt252
blk0 (root):
Statements:
End:
  Goto(blk2, {})

blk1:
Statements:
End:
  Return(v1)

blk2:
Statements:
  (v2: core::felt252) <- -1u
End:
  Goto(blk4, {})

blk3:
Statements:
End:
  Goto(blk1, {v3 -> v1})

blk4:
Statements:
  (v4: core::felt252) <- core::felt252_mul(v0, v2)
End:
  Goto(blk3, {v4 -> v3})

//! > lowering_diagnostics

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

//! > Test generic function inlining.

//! > test_runner_name
test_function_inlining

//! > function
fn foo(val: Option::<felt252>) -> felt252 {
  bar(val, 2)
}

//! > function_name
foo

//! > module_code
/// If `val` is `Option::Some(x)`, returns `x`. Otherwise, panics.
#[inline]
fn bar<T, impl TDrop: Drop::<T>>(val: Option::<T>, val2: T) -> T {
    match val {
        Option::Some(x) => x,
        Option::None => val2,
    }
}

//! > semantic_diagnostics

//! > before
Parameters: v0: core::option::Option::<core::felt252>
blk0 (root):
Statements:
  (v1: core::felt252) <- 2u
  (v2: core::felt252) <- test::bar::<core::felt252, core::felt252Drop>(v0, v1)
End:
  Return(v2)

//! > after
Parameters: v0: core::option::Option::<core::felt252>
blk0 (root):
Statements:
  (v1: core::felt252) <- 2u
End:
  Goto(blk2, {})

blk1:
Statements:
End:
  Return(v2)

blk2:
Statements:
End:
  Match(match_enum(v0) {
    Option::Some(v3) => blk3,
    Option::None(v4) => blk4,
  })

blk3:
Statements:
End:
  Goto(blk5, {v3 -> v5})

blk4:
Statements:
End:
  Goto(blk5, {v1 -> v5})

blk5:
Statements:
End:
  Goto(blk1, {v5 -> v2})

//! > lowering_diagnostics

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

//! > Test inlining same arg twice.

//! > test_runner_name
test_function_inlining

//! > function
fn foo(n: felt252) -> felt252 {
  bar(n, n)
}

//! > function_name
foo

//! > module_code
#[inline(always)]
fn bar(a: felt252, b: felt252) -> felt252  {
  a + b
}

//! > semantic_diagnostics

//! > before
Parameters: v0: core::felt252
blk0 (root):
Statements:
  (v1: core::felt252) <- test::bar(v0, v0)
End:
  Return(v1)

//! > after
Parameters: v0: core::felt252
blk0 (root):
Statements:
End:
  Goto(blk2, {})

blk1:
Statements:
End:
  Return(v1)

blk2:
Statements:
End:
  Goto(blk4, {})

blk3:
Statements:
End:
  Goto(blk1, {v2 -> v1})

blk4:
Statements:
  (v3: core::felt252) <- core::felt252_add(v0, v0)
End:
  Goto(blk3, {v3 -> v2})

//! > lowering_diagnostics

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

//! > Test inlining.

//! > test_runner_name
test_function_inlining

//! > function
fn foo(a: felt252, b: felt252) -> felt252 {
  bar(a + b, b)
}

//! > function_name
foo

//! > module_code
#[inline(always)]
fn bar(a: felt252, b: felt252) -> felt252 implicits()  {
  bar2(a, b) + bar2(b, a)
}

#[inline(always)]
fn bar2(a: felt252, b: felt252) -> felt252 implicits()  {
   a * b
}

//! > semantic_diagnostics

//! > before
Parameters: v0: core::felt252, v1: core::felt252
blk0 (root):
Statements:
  (v2: core::felt252) <- core::Felt252Add::add(v0, v1)
  (v3: core::felt252) <- test::bar(v2, v1)
End:
  Return(v3)

//! > after
Parameters: v0: core::felt252, v1: core::felt252
blk0 (root):
Statements:
End:
  Goto(blk2, {})

blk1:
Statements:
End:
  Goto(blk4, {})

blk2:
Statements:
  (v4: core::felt252) <- core::felt252_add(v0, v1)
End:
  Goto(blk1, {v4 -> v2})

blk3:
Statements:
End:
  Return(v3)

blk4:
Statements:
End:
  Goto(blk6, {})

blk5:
Statements:
End:
  Goto(blk8, {})

blk6:
Statements:
End:
  Goto(blk10, {})

blk7:
Statements:
End:
  Goto(blk12, {})

blk8:
Statements:
End:
  Goto(blk14, {})

blk9:
Statements:
End:
  Goto(blk5, {v8 -> v5})

blk10:
Statements:
  (v10: core::felt252) <- core::felt252_mul(v2, v1)
End:
  Goto(blk9, {v10 -> v8})

blk11:
Statements:
End:
  Goto(blk3, {v7 -> v3})

blk12:
Statements:
  (v11: core::felt252) <- core::felt252_add(v5, v6)
End:
  Goto(blk11, {v11 -> v7})

blk13:
Statements:
End:
  Goto(blk7, {v9 -> v6})

blk14:
Statements:
  (v12: core::felt252) <- core::felt252_mul(v1, v2)
End:
  Goto(blk13, {v12 -> v9})

//! > lowering_diagnostics

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

//! > Test recursive inlining.

//! > test_runner_name
test_function_inlining

//! > function
fn foo(a: felt252) -> felt252 {
  first(a)
}

//! > function_name
foo

//! > module_code
#[inline(always)]
fn first(a: felt252) -> felt252 {
  second(a)
}

#[inline(always)]
fn second(a: felt252) -> felt252 {
  third(a)
}

#[inline(always)]
fn third(a: felt252) -> felt252 {
   a * a
}

//! > semantic_diagnostics

//! > before
Parameters: v0: core::felt252
blk0 (root):
Statements:
  (v1: core::felt252) <- test::first(v0)
End:
  Return(v1)

//! > after
Parameters: v0: core::felt252
blk0 (root):
Statements:
End:
  Goto(blk2, {})

blk1:
Statements:
End:
  Return(v1)

blk2:
Statements:
End:
  Goto(blk4, {})

blk3:
Statements:
End:
  Goto(blk1, {v2 -> v1})

blk4:
Statements:
End:
  Goto(blk6, {})

blk5:
Statements:
End:
  Goto(blk3, {v3 -> v2})

blk6:
Statements:
End:
  Goto(blk8, {})

blk7:
Statements:
End:
  Goto(blk5, {v4 -> v3})

blk8:
Statements:
  (v5: core::felt252) <- core::felt252_mul(v0, v0)
End:
  Goto(blk7, {v5 -> v4})

//! > lowering_diagnostics

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

//! > Test impl inlining.

//! > test_runner_name
test_function_inlining

//! > function
fn foo() {
  let mut arr = array![];
  arr.append(5)
}

//! > function_name
foo

//! > module_code

//! > semantic_diagnostics

//! > before
Parameters:
blk0 (root):
Statements:
  (v0: core::array::Array::<core::felt252>) <- core::array::ArrayImpl::<core::felt252>::new()
  (v1: core::felt252) <- 5u
  (v3: core::array::Array::<core::felt252>, v2: ()) <- core::array::ArrayImpl::<core::felt252>::append(v0, v1)
End:
  Return(v2)

//! > after
Parameters:
blk0 (root):
Statements:
End:
  Goto(blk2, {})

blk1:
Statements:
  (v1: core::felt252) <- 5u
End:
  Goto(blk4, {})

blk2:
Statements:
  (v4: core::array::Array::<core::felt252>) <- core::array::array_new::<core::felt252>()
End:
  Goto(blk1, {v4 -> v0})

blk3:
Statements:
End:
  Return(v2)

blk4:
Statements:
  (v5: core::array::Array::<core::felt252>) <- core::array::array_append::<core::felt252>(v0, v1)
  (v6: ()) <- struct_construct()
End:
  Goto(blk3, {v5 -> v3, v6 -> v2})

//! > lowering_diagnostics

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

//! > Test inlining of a function with an early return.

//! > test_runner_name
test_function_inlining

//! > function
fn foo(a: felt252) -> felt252 {
  if a == 2 {
    bar(a)
  } else {
    a
  }
}

//! > function_name
foo

//! > module_code
#[inline(always)]
fn bar(a: felt252) -> felt252 {
  if a == 0 {
    return 1;
  }
  0
}

//! > before
Parameters: v0: core::felt252
blk0 (root):
Statements:
  (v1: core::felt252) <- 2u
  (v2: core::felt252) <- core::Felt252Sub::sub(v0, v1)
End:
  Match(match core::felt252_is_zero(v2) {
    IsZeroResult::Zero => blk1,
    IsZeroResult::NonZero(v4) => blk2,
  })

blk1:
Statements:
  (v3: core::felt252) <- test::bar(v0)
End:
  Goto(blk3, {v3 -> v5})

blk2:
Statements:
End:
  Goto(blk3, {v0 -> v5})

blk3:
Statements:
End:
  Return(v5)

//! > after
Parameters: v0: core::felt252
blk0 (root):
Statements:
  (v1: core::felt252) <- 2u
End:
  Goto(blk5, {})

blk1:
Statements:
End:
  Goto(blk7, {})

blk2:
Statements:
End:
  Goto(blk3, {v0 -> v5})

blk3:
Statements:
End:
  Return(v5)

blk4:
Statements:
End:
  Match(match core::felt252_is_zero(v2) {
    IsZeroResult::Zero => blk1,
    IsZeroResult::NonZero(v4) => blk2,
  })

blk5:
Statements:
  (v6: core::felt252) <- core::felt252_sub(v0, v1)
End:
  Goto(blk4, {v6 -> v2})

blk6:
Statements:
End:
  Goto(blk3, {v3 -> v5})

blk7:
Statements:
End:
  Match(match core::felt252_is_zero(v0) {
    IsZeroResult::Zero => blk8,
    IsZeroResult::NonZero(v7) => blk9,
  })

blk8:
Statements:
  (v8: core::felt252) <- 1u
End:
  Goto(blk6, {v8 -> v3})

blk9:
Statements:
End:
  Goto(blk10, {})

blk10:
Statements:
  (v9: core::felt252) <- 0u
End:
  Goto(blk6, {v9 -> v3})

//! > lowering_diagnostics

//! > semantic_diagnostics

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

//! > Test inlining heuristic

//! > test_runner_name
test_function_inlining

//! > function
fn foo(a: felt252) -> felt252 {
  bar(a) + bar2(a)
}

//! > function_name
foo

//! > module_code
fn bar(a: felt252) -> felt252 {
  bar2(a)
}

fn bar2(a: felt252) -> felt252 {
  1
}

//! > before
Parameters: v0: core::felt252
blk0 (root):
Statements:
  (v1: core::felt252) <- test::bar(v0)
  (v2: core::felt252) <- test::bar2(v0)
  (v3: core::felt252) <- core::Felt252Add::add(v1, v2)
End:
  Return(v3)

//! > after
Parameters: v0: core::felt252
blk0 (root):
Statements:
End:
  Goto(blk2, {})

blk1:
Statements:
End:
  Goto(blk4, {})

blk2:
Statements:
End:
  Goto(blk6, {})

blk3:
Statements:
End:
  Goto(blk8, {})

blk4:
Statements:
  (v5: core::felt252) <- 1u
End:
  Goto(blk3, {v5 -> v2})

blk5:
Statements:
End:
  Goto(blk1, {v4 -> v1})

blk6:
Statements:
  (v6: core::felt252) <- 1u
End:
  Goto(blk5, {v6 -> v4})

blk7:
Statements:
End:
  Return(v3)

blk8:
Statements:
  (v7: core::felt252) <- core::felt252_add(v1, v2)
End:
  Goto(blk7, {v7 -> v3})

//! > lowering_diagnostics

//! > semantic_diagnostics

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

//! > Test preventing inlining heuristic

//! > test_runner_name
test_function_inlining

//! > function
fn foo(a: felt252) -> felt252 {
  bar(a) + bar2(a)
}

//! > function_name
foo

//! > module_code
#[inline(never)]
fn bar(a: felt252) -> felt252 {
  bar2(a)
}

#[inline(never)]
fn bar2(a: felt252) -> felt252 {
  1
}

//! > before
Parameters: v0: core::felt252
blk0 (root):
Statements:
  (v1: core::felt252) <- test::bar(v0)
  (v2: core::felt252) <- test::bar2(v0)
  (v3: core::felt252) <- core::Felt252Add::add(v1, v2)
End:
  Return(v3)

//! > after
Parameters: v0: core::felt252
blk0 (root):
Statements:
  (v1: core::felt252) <- test::bar(v0)
  (v2: core::felt252) <- test::bar2(v0)
End:
  Goto(blk2, {})

blk1:
Statements:
End:
  Return(v3)

blk2:
Statements:
  (v4: core::felt252) <- core::felt252_add(v1, v2)
End:
  Goto(blk1, {v4 -> v3})

//! > lowering_diagnostics

//! > semantic_diagnostics

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

//! > Test returning an input variable as is (not in the last block).

//! > test_runner_name
test_function_inlining

//! > function
fn foo() -> felt252 {
  bar(0)
}

//! > function_name
foo

//! > module_code
#[inline(always)]
fn bar(a: felt252) -> felt252 {
  if a == 0 {
    return a;
  }
  1
}

//! > semantic_diagnostics

//! > lowering_diagnostics

//! > before
Parameters:
blk0 (root):
Statements:
  (v0: core::felt252) <- 0u
  (v1: core::felt252) <- test::bar(v0)
End:
  Return(v1)

//! > after
Parameters:
blk0 (root):
Statements:
  (v0: core::felt252) <- 0u
End:
  Goto(blk2, {})

blk1:
Statements:
End:
  Return(v1)

blk2:
Statements:
End:
  Match(match core::felt252_is_zero(v0) {
    IsZeroResult::Zero => blk3,
    IsZeroResult::NonZero(v2) => blk4,
  })

blk3:
Statements:
End:
  Goto(blk1, {v0 -> v1})

blk4:
Statements:
End:
  Goto(blk5, {})

blk5:
Statements:
  (v3: core::felt252) <- 1u
End:
  Goto(blk1, {v3 -> v1})

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

//! > Test inlining of identity function.

//! > test_runner_name
test_function_inlining

//! > function
fn foo(n: felt252) -> felt252 {
  identity(n)
}

//! > function_name
foo

//! > module_code
#[inline(always)]
fn identity(n: felt252) -> felt252 {
  n
}

//! > semantic_diagnostics

//! > before
Parameters: v0: core::felt252
blk0 (root):
Statements:
  (v1: core::felt252) <- test::identity(v0)
End:
  Return(v1)

//! > after
Parameters: v0: core::felt252
blk0 (root):
Statements:
End:
  Goto(blk2, {})

blk1:
Statements:
End:
  Return(v1)

blk2:
Statements:
End:
  Goto(blk1, {v0 -> v1})

//! > lowering_diagnostics

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

//! > Test match where is there is a return in one branch.

//! > Motivation:
// The goal of this test is to test the block renaming logic.
// A panicable function can have a block with a low `block_id` with a match_arm that goes
// to a higher 'block_id'.
// We want to test this outside of the outer scope as the last block is rebuild last.

//! > test_runner_name
test_function_inlining

//! > function
fn foo(a: u128, b: u128) -> u128 {
    bar1(a, b)
}

//! > function_name
foo

//! > module_code
#[inline(always)]
fn bar1(a: u128, b: u128) -> u128 {
   if a == 1_u128 {
      return bar2(b, a);
   }
   a
}

#[inline(always)]
fn bar2(a: u128, b: u128) -> u128 {
    a + b
}

//! > semantic_diagnostics

//! > before
Parameters: v0: core::integer::u128, v1: core::integer::u128
blk0 (root):
Statements:
  (v2: core::integer::u128) <- test::bar1(v0, v1)
End:
  Return(v2)

//! > after
Parameters: v0: core::integer::u128, v1: core::integer::u128
blk0 (root):
Statements:
End:
  Goto(blk2, {})

blk1:
Statements:
End:
  Return(v2)

blk2:
Statements:
  (v3: core::integer::u128, v4: @core::integer::u128) <- snapshot(v0)
  (v5: core::integer::u128) <- 1u
  (v6: core::integer::u128, v7: @core::integer::u128) <- snapshot(v5)
End:
  Goto(blk7, {})

blk3:
Statements:
End:
  Goto(blk12, {})

blk4:
Statements:
End:
  Goto(blk5, {})

blk5:
Statements:
End:
  Goto(blk1, {v3 -> v2})

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

blk7:
Statements:
  (v12: core::integer::u128) <- desnap(v4)
  (v13: core::integer::u128) <- desnap(v7)
End:
  Match(match core::integer::u128_eq(v12, v13) {
    bool::False => blk8,
    bool::True => blk9,
  })

blk8:
Statements:
  (v14: ()) <- struct_construct()
  (v15: core::bool) <- bool::False(v14)
End:
  Goto(blk10, {v15 -> v16})

blk9:
Statements:
  (v17: ()) <- struct_construct()
  (v18: core::bool) <- bool::True(v17)
End:
  Goto(blk10, {v18 -> v16})

blk10:
Statements:
End:
  Goto(blk6, {v16 -> v8})

blk11:
Statements:
End:
  Goto(blk1, {v11 -> v2})

blk12:
Statements:
  (v19: core::integer::u128) <- core::integer::U128Add::add(v1, v3)
End:
  Goto(blk11, {v19 -> v11})

//! > lowering_diagnostics

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

//! > Test inlining a function where the root block does not return.

//! > test_runner_name
test_function_inlining

//! > function_name
foo

//! > function
fn foo(n: felt252) -> felt252 {
  bar(n)
}

//! > module_code
#[inline(always)]
fn bar(n: felt252) -> felt252 {
  if n == 0 {
    return 1;
  } else {
    return 1;
  }
}

//! > semantic_diagnostics

//! > before
Parameters: v0: core::felt252
blk0 (root):
Statements:
  (v1: core::felt252) <- test::bar(v0)
End:
  Return(v1)

//! > after
Parameters: v0: core::felt252
blk0 (root):
Statements:
End:
  Goto(blk2, {})

blk1:
Statements:
End:
  Return(v1)

blk2:
Statements:
End:
  Match(match core::felt252_is_zero(v0) {
    IsZeroResult::Zero => blk3,
    IsZeroResult::NonZero(v2) => blk4,
  })

blk3:
Statements:
  (v3: core::felt252) <- 1u
End:
  Goto(blk1, {v3 -> v1})

blk4:
Statements:
  (v4: core::felt252) <- 1u
End:
  Goto(blk1, {v4 -> v1})

//! > lowering_diagnostics

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

//! > test #[inline] with indirect self call.

//! > Motivation:
//! #[inline] functions should inline a function unless it is recursively called by itself, even
//! indirectly. In this case, the function bar should be inlined, but not the inner call to foo.

//! > test_runner_name
test_function_inlining

//! > function_name
foo

//! > function
#[inline]
fn foo(n: felt252) -> felt252 {
  bar(n)
}

//! > module_code
#[inline]
fn bar(n: felt252) -> felt252 {
  if n == 0 {
    foo(n-1)
  } else {
    return 1;
  }
}

//! > semantic_diagnostics

//! > before
Parameters: v0: core::felt252
blk0 (root):
Statements:
  (v1: core::felt252) <- test::bar(v0)
End:
  Return(v1)

//! > after
Parameters: v0: core::felt252
blk0 (root):
Statements:
End:
  Goto(blk2, {})

blk1:
Statements:
End:
  Return(v1)

blk2:
Statements:
End:
  Match(match core::felt252_is_zero(v0) {
    IsZeroResult::Zero => blk3,
    IsZeroResult::NonZero(v2) => blk4,
  })

blk3:
Statements:
  (v3: core::felt252) <- 1u
End:
  Goto(blk7, {})

blk4:
Statements:
  (v7: core::felt252) <- 1u
End:
  Goto(blk1, {v7 -> v1})

blk5:
Statements:
End:
  Goto(blk1, {v6 -> v1})

blk6:
Statements:
  (v5: core::felt252) <- test::foo(v4)
End:
  Goto(blk5, {v5 -> v6})

blk7:
Statements:
  (v8: core::felt252) <- core::felt252_sub(v0, v3)
End:
  Goto(blk6, {v8 -> v4})

//! > lowering_diagnostics

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

//! > test #[inline] with direct self call.

//! > test_runner_name
test_function_inlining

//! > function_name
foo

//! > function
#[inline]
fn foo(n: felt252) -> felt252 {
  foo(n)
}

//! > module_code

//! > semantic_diagnostics

//! > before
Parameters: v0: core::felt252
blk0 (root):
Statements:
  (v1: core::felt252) <- test::foo(v0)
End:
  Return(v1)

//! > after
Parameters: v0: core::felt252
blk0 (root):
Statements:
  (v1: core::felt252) <- test::foo(v0)
End:
  Return(v1)

//! > lowering_diagnostics

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

//! > test #[inline] with direct self call in a called function.

//! > test_runner_name
test_function_inlining

//! > function_name
foo

//! > function
#[inline]
fn foo(n: felt252) -> felt252 {
  bar(n)
}

//! > module_code
#[inline]
fn bar(n: felt252) -> felt252 {
  if n == 0 {
    bar(n-1)
  } else {
    return 1;
  }
}

//! > semantic_diagnostics

//! > before
Parameters: v0: core::felt252
blk0 (root):
Statements:
  (v1: core::felt252) <- test::bar(v0)
End:
  Return(v1)

//! > after
Parameters: v0: core::felt252
blk0 (root):
Statements:
End:
  Goto(blk2, {})

blk1:
Statements:
End:
  Return(v1)

blk2:
Statements:
End:
  Match(match core::felt252_is_zero(v0) {
    IsZeroResult::Zero => blk3,
    IsZeroResult::NonZero(v2) => blk4,
  })

blk3:
Statements:
  (v3: core::felt252) <- 1u
End:
  Goto(blk7, {})

blk4:
Statements:
  (v7: core::felt252) <- 1u
End:
  Goto(blk1, {v7 -> v1})

blk5:
Statements:
End:
  Goto(blk1, {v6 -> v1})

blk6:
Statements:
  (v5: core::felt252) <- test::bar(v4)
End:
  Goto(blk5, {v5 -> v6})

blk7:
Statements:
  (v8: core::felt252) <- core::felt252_sub(v0, v3)
End:
  Goto(blk6, {v8 -> v4})

//! > lowering_diagnostics

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

//! > test #[inline] with direct self call inside two levels of called functions.

//! > test_runner_name
test_function_inlining

//! > function_name
foo

//! > function
#[inline]
fn foo(n: felt252) -> felt252 {
  bar(n)
}

//! > module_code
#[inline]
fn bar(n: felt252) -> felt252 {
  baz(n)
}

#[inline]
fn baz(n: felt252) -> felt252 {
  if n == 0 {
    baz(n-1)
  } else {
    return 1;
  }
}

//! > semantic_diagnostics

//! > before
Parameters: v0: core::felt252
blk0 (root):
Statements:
  (v1: core::felt252) <- test::bar(v0)
End:
  Return(v1)

//! > after
Parameters: v0: core::felt252
blk0 (root):
Statements:
End:
  Goto(blk2, {})

blk1:
Statements:
End:
  Return(v1)

blk2:
Statements:
End:
  Goto(blk4, {})

blk3:
Statements:
End:
  Goto(blk1, {v2 -> v1})

blk4:
Statements:
End:
  Match(match core::felt252_is_zero(v0) {
    IsZeroResult::Zero => blk5,
    IsZeroResult::NonZero(v3) => blk6,
  })

blk5:
Statements:
  (v4: core::felt252) <- 1u
End:
  Goto(blk9, {})

blk6:
Statements:
  (v8: core::felt252) <- 1u
End:
  Goto(blk3, {v8 -> v2})

blk7:
Statements:
End:
  Goto(blk3, {v7 -> v2})

blk8:
Statements:
  (v6: core::felt252) <- test::baz(v5)
End:
  Goto(blk7, {v6 -> v7})

blk9:
Statements:
  (v9: core::felt252) <- core::felt252_sub(v0, v4)
End:
  Goto(blk8, {v9 -> v5})

//! > lowering_diagnostics

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

//! > test #[inline] with call a callee from a called function.

//! > test_runner_name
test_function_inlining

//! > function_name
foo

//! > function
#[inline]
fn foo(n: felt252) -> felt252 {
  bar(n)
}

//! > module_code
#[inline]
fn bar(n: felt252) -> felt252 {
  baz(n)
}

#[inline]
fn baz(n: felt252) -> felt252 {
  if n == 0 {
    bar(n-1)
  } else {
    return 1;
  }
}

//! > semantic_diagnostics

//! > before
Parameters: v0: core::felt252
blk0 (root):
Statements:
  (v1: core::felt252) <- test::bar(v0)
End:
  Return(v1)

//! > after
Parameters: v0: core::felt252
blk0 (root):
Statements:
End:
  Goto(blk2, {})

blk1:
Statements:
End:
  Return(v1)

blk2:
Statements:
End:
  Goto(blk4, {})

blk3:
Statements:
End:
  Goto(blk1, {v2 -> v1})

blk4:
Statements:
End:
  Match(match core::felt252_is_zero(v0) {
    IsZeroResult::Zero => blk5,
    IsZeroResult::NonZero(v3) => blk6,
  })

blk5:
Statements:
  (v4: core::felt252) <- 1u
End:
  Goto(blk9, {})

blk6:
Statements:
  (v8: core::felt252) <- 1u
End:
  Goto(blk3, {v8 -> v2})

blk7:
Statements:
End:
  Goto(blk3, {v7 -> v2})

blk8:
Statements:
  (v6: core::felt252) <- test::bar(v5)
End:
  Goto(blk7, {v6 -> v7})

blk9:
Statements:
  (v9: core::felt252) <- core::felt252_sub(v0, v4)
End:
  Goto(blk8, {v9 -> v5})

//! > lowering_diagnostics

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

//! > test #[inline] with call a two levels above callee from a called function.

//! > test_runner_name
test_function_inlining

//! > function_name
foo

//! > function
#[inline]
fn foo(n: felt252) -> felt252 {
  bar(n)
}

//! > module_code
#[inline]
fn bar(n: felt252) -> felt252 {
  baz(n)
}

#[inline]
fn baz(n: felt252) -> felt252 {
  if n == 0 {
    foo(n-1)
  } else {
    return 1;
  }
}

//! > semantic_diagnostics

//! > before
Parameters: v0: core::felt252
blk0 (root):
Statements:
  (v1: core::felt252) <- test::bar(v0)
End:
  Return(v1)

//! > after
Parameters: v0: core::felt252
blk0 (root):
Statements:
End:
  Goto(blk2, {})

blk1:
Statements:
End:
  Return(v1)

blk2:
Statements:
End:
  Goto(blk4, {})

blk3:
Statements:
End:
  Goto(blk1, {v2 -> v1})

blk4:
Statements:
End:
  Match(match core::felt252_is_zero(v0) {
    IsZeroResult::Zero => blk5,
    IsZeroResult::NonZero(v3) => blk6,
  })

blk5:
Statements:
  (v4: core::felt252) <- 1u
End:
  Goto(blk9, {})

blk6:
Statements:
  (v8: core::felt252) <- 1u
End:
  Goto(blk3, {v8 -> v2})

blk7:
Statements:
End:
  Goto(blk3, {v7 -> v2})

blk8:
Statements:
  (v6: core::felt252) <- test::foo(v5)
End:
  Goto(blk7, {v6 -> v7})

blk9:
Statements:
  (v9: core::felt252) <- core::felt252_sub(v0, v4)
End:
  Goto(blk8, {v9 -> v5})

//! > lowering_diagnostics

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

//! > test #[inline] with call a function twice.

//! > test_runner_name
test_function_inlining

//! > function_name
foo

//! > function
fn foo(n: felt252) -> felt252 {
  bar(n) + bar(n)
}

//! > module_code
#[inline]
fn bar(n: felt252) -> felt252 {
  n
}

//! > semantic_diagnostics

//! > before
Parameters: v0: core::felt252
blk0 (root):
Statements:
  (v1: core::felt252) <- test::bar(v0)
  (v2: core::felt252) <- test::bar(v0)
  (v3: core::felt252) <- core::Felt252Add::add(v1, v2)
End:
  Return(v3)

//! > after
Parameters: v0: core::felt252
blk0 (root):
Statements:
End:
  Goto(blk2, {})

blk1:
Statements:
End:
  Goto(blk4, {})

blk2:
Statements:
End:
  Goto(blk1, {v0 -> v1})

blk3:
Statements:
End:
  Goto(blk6, {})

blk4:
Statements:
End:
  Goto(blk3, {v0 -> v2})

blk5:
Statements:
End:
  Return(v3)

blk6:
Statements:
  (v4: core::felt252) <- core::felt252_add(v1, v2)
End:
  Goto(blk5, {v4 -> v3})

//! > lowering_diagnostics
