//! > Test calling trait function.

//! > test_runner_name
test_function_lowering(expect_diagnostics: false)

//! > function_code
fn foo() {
    immovable(5.foo(true));
    immovable(MyTrait::foo(6, false));
}

//! > function_name
foo

//! > module_code
trait MyTrait<T> {
    fn foo<S>(self: T, y: S) -> (T, S);
}
impl MyImpl of MyTrait<felt252> {
    #[inline(always)]
    fn foo<S>(self: felt252, y: S) -> (felt252, S) {
        (self, y)
    }
}

extern fn immovable<T>(t: T) -> T nopanic;

//! > semantic_diagnostics

//! > lowering_diagnostics

//! > lowering_flat
Parameters:
blk0 (root):
Statements:
  (v0: ()) <- struct_construct()
  (v1: core::felt252) <- 5
  (v2: core::bool) <- bool::True(v0)
  (v3: (core::felt252, core::bool)) <- struct_construct(v1, v2)
  (v4: core::felt252, v5: core::bool) <- test::immovable::<(core::felt252, core::bool)>(v3)
  (v6: core::felt252) <- 6
  (v7: core::bool) <- bool::False(v0)
  (v8: (core::felt252, core::bool)) <- struct_construct(v6, v7)
  (v9: core::felt252, v10: core::bool) <- test::immovable::<(core::felt252, core::bool)>(v8)
End:
  Return()

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

//! > Test generic structs.

//! > test_runner_name
test_function_lowering(expect_diagnostics: false)

//! > function_code
fn foo() -> felt252 {
    let q = Query { data: 1 };
    let Query { data } = q;
    Query { data: 2 }.data + data
}

//! > function_name
foo

//! > module_code
struct Query<V> {
    data: V,
}

//! > semantic_diagnostics

//! > lowering_diagnostics

//! > lowering_flat
Parameters:
blk0 (root):
Statements:
  (v0: core::felt252) <- 3
End:
  Return(v0)

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

//! > Test generic impls.

//! > test_runner_name
test_function_lowering(expect_diagnostics: false)

//! > function_code
fn foo() {
    bar::<MyImpl>()
}

//! > function_name
foo

//! > module_code
fn bar<impl Imp: MyTrait>() {
    Imp::foo()
}
trait MyTrait {
    fn foo();
}
impl MyImpl of MyTrait {
    fn foo() {}
}

//! > semantic_diagnostics

//! > lowering_diagnostics

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

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

//! > Test generic impls for type info.

//! > test_runner_name
test_function_lowering(expect_diagnostics: false)

//! > function_code
fn foo() {
    MyTrait::bar(5);
}

//! > function_name
foo

//! > module_code
trait MyTrait<T> {
    fn bar(x: T);
}
impl MyImpl<T, impl TDrop: Drop<T>> of MyTrait<T> {
    #[inline(never)]
    fn bar(x: T) {}
}

//! > semantic_diagnostics

//! > lowering_diagnostics

//! > lowering_flat
Parameters:
blk0 (root):
Statements:
  (v0: core::felt252) <- 5
  () <- test::MyImpl::<core::felt252, core::felt252Drop>::bar(v0)
End:
  Return()

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

//! > Path in generic literal consts.

//! > test_runner_name
test_function_lowering(expect_diagnostics: false)

//! > function_code
fn foo() -> felt252 {
    felt252_const::<one>()
}

//! > function_name
foo

//! > module_code
const one: felt252 = 1;

//! > semantic_diagnostics

//! > lowering_diagnostics

//! > lowering_flat
Parameters:
blk0 (root):
Statements:
  (v0: core::felt252) <- core::felt252_const::<1>()
End:
  Return(v0)

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

//! > generic param in expression

//! > test_runner_name
test_function_lowering(expect_diagnostics: false)

//! > function_code
fn foo() -> felt252 {
    bar::<{ 1 + 2 }>() + bar::<2>()
}

//! > function_name
foo

//! > module_code
fn bar<const N: felt252>() -> felt252 {
    N + 5
}

//! > semantic_diagnostics

//! > lowering_diagnostics

//! > lowering_flat
Parameters:
blk0 (root):
Statements:
  (v0: core::felt252) <- 15
End:
  Return(v0)

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

//! > Test generic const types

//! > test_runner_name
test_function_lowering(expect_diagnostics: false)

//! > function_code
fn foo() -> MyStruct<9> {
    let s1 = foo_helper();
    s1.bar();
    s1.bar();
    s1
}

//! > function_name
foo

//! > module_code
#[derive(Drop, Copy)]
struct MyStruct<const N: felt252> {}
trait MyTrait<T> {
    fn bar(self: @T) -> felt252;
}
impl MyStructMyTrait<const N: felt252> of MyTrait<MyStruct<N>> {
    #[inline(never)]
    fn bar(self: @MyStruct::<N>) -> felt252 {
        N
    }
}

#[inline(never)]
fn foo_helper<const N: felt252>() -> MyStruct<N> {
    MyStruct::<N> {}
}

//! > semantic_diagnostics

//! > lowering_diagnostics

//! > lowering_flat
Parameters:
blk0 (root):
Statements:
  (v0: test::MyStruct::<9>) <- test::foo_helper::<9>()
  (v1: test::MyStruct::<9>, v2: @test::MyStruct::<9>) <- snapshot(v0)
  (v3: core::felt252) <- test::MyStructMyTrait::<9>::bar(v2)
  (v4: core::felt252) <- test::MyStructMyTrait::<9>::bar(v2)
End:
  Return(v0)
