//! > Simple match

//! > test_runner_name
test_create_graph(expect_diagnostics: true)

//! > function_code
fn foo(color: Color) -> felt252 {
    match color {
        Color::Red | Color::Green(_) => 1,
        Color::Red(_) | Color::Blue => 2,
        Color::Blue | Color::Green => 3,
        _ => 4,
    }
}

//! > module_code
enum Color {
    Red,
    Green,
    Blue,
    Black,
    White,
}

//! > graph
Root: 5
5 EvaluateExpr { expr: ExprId(0), var_id: v0, next: NodeId(4) }
4 EnumMatch { matched_var: v0, variants: (NodeId(0), v1), (NodeId(0), v2), (NodeId(1), v3), (NodeId(3), v4), (NodeId(3), v5)}
3 ArmExpr { expr: ExprId(4) }
2 ArmExpr { expr: ExprId(3) }
1 ArmExpr { expr: ExprId(2) }
0 ArmExpr { expr: ExprId(1) }

//! > semantic_diagnostics

//! > lowering_diagnostics
warning[E3004]: Unreachable pattern arm.
 --> lib.cairo:12:39
        Color::Blue | Color::Green => 3,
                                      ^

//! > lowered
Parameters: v0: test::Color
blk0 (root):
Statements:
End:
  Match(match_enum(v0) {
    Color::Red(v1) => blk1,
    Color::Green(v2) => blk2,
    Color::Blue(v3) => blk3,
    Color::Black(v4) => blk4,
    Color::White(v5) => blk5,
  })

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

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

blk3:
Statements:
  (v7: core::felt252) <- 2
End:
  Goto(blk8, {v7 -> v9})

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

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

blk6:
Statements:
  (v6: core::felt252) <- 4
End:
  Goto(blk8, {v6 -> v9})

blk7:
Statements:
  (v8: core::felt252) <- 1
End:
  Goto(blk8, {v8 -> v9})

blk8:
Statements:
End:
  Return(v9)

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

//! > Match with pattern binding

//! > test_runner_name
test_create_graph(expect_diagnostics: false)

//! > function_code
fn foo(color: Color) -> felt252 {
    match color {
        Color::Red(x) | Color::Green(x) => 2 * x,
        Color::Blue(x) => x,
        _ => 0,
    }
}

//! > module_code
enum Color {
    Red: felt252,
    Green: felt252,
    Blue: felt252,
    Black,
}

//! > graph
Root: 7
7 EvaluateExpr { expr: ExprId(0), var_id: v0, next: NodeId(6) }
6 EnumMatch { matched_var: v0, variants: (NodeId(3), v1), (NodeId(4), v2), (NodeId(5), v3), (NodeId(2), v4)}
5 BindVar { input: v3, output: PatternVarId(2), next: NodeId(1) }
4 BindVar { input: v2, output: PatternVarId(1), next: NodeId(0) }
3 BindVar { input: v1, output: PatternVarId(0), next: NodeId(0) }
2 ArmExpr { expr: ExprId(5) }
1 ArmExpr { expr: ExprId(4) }
0 ArmExpr { expr: ExprId(3) }

//! > semantic_diagnostics

//! > lowering_diagnostics

//! > lowered
Parameters: v0: test::Color
blk0 (root):
Statements:
End:
  Match(match_enum(v0) {
    Color::Red(v1) => blk1,
    Color::Green(v2) => blk2,
    Color::Blue(v3) => blk3,
    Color::Black(v4) => blk4,
  })

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

blk2:
Statements:
End:
  Goto(blk5, {v2 -> v6})

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

blk4:
Statements:
  (v5: core::felt252) <- 0
End:
  Goto(blk6, {v5 -> v9})

blk5:
Statements:
  (v7: core::felt252) <- 2
  (v8: core::felt252) <- core::Felt252Mul::mul(v7, v6)
End:
  Goto(blk6, {v8 -> v9})

blk6:
Statements:
End:
  Return(v9)

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

//! > Tuple of enums

//! > test_runner_name
test_create_graph(expect_diagnostics: false)

//! > function_code
fn foo(color: (Color, Color)) -> felt252 {
    match color {
        (Color::Red, _) => 1,
        (_, Color::Red) => 2,
        _ => 3,
    }
}

//! > module_code
enum Color {
    Red,
    Green,
    Blue,
}

//! > graph
Root: 6
6 EvaluateExpr { expr: ExprId(0), var_id: v0, next: NodeId(5) }
5 Deconstruct { input: v0, outputs: [v1, v2], next: NodeId(4) }
4 EnumMatch { matched_var: v1, variants: (NodeId(0), v3), (NodeId(3), v7), (NodeId(3), v11)}
3 EnumMatch { matched_var: v2, variants: (NodeId(1), v8), (NodeId(2), v9), (NodeId(2), v10)}
2 ArmExpr { expr: ExprId(3) }
1 ArmExpr { expr: ExprId(2) }
0 ArmExpr { expr: ExprId(1) }

//! > semantic_diagnostics

//! > lowering_diagnostics

//! > lowered
Parameters: v0: (test::Color, test::Color)
blk0 (root):
Statements:
  (v1: test::Color, v2: test::Color) <- struct_destructure(v0)
End:
  Match(match_enum(v1) {
    Color::Red(v3) => blk1,
    Color::Green(v4) => blk2,
    Color::Blue(v5) => blk3,
  })

blk1:
Statements:
  (v11: core::felt252) <- 1
End:
  Goto(blk9, {v11 -> v12})

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

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

blk4:
Statements:
End:
  Match(match_enum(v2) {
    Color::Red(v6) => blk5,
    Color::Green(v7) => blk6,
    Color::Blue(v8) => blk7,
  })

blk5:
Statements:
  (v10: core::felt252) <- 2
End:
  Goto(blk9, {v10 -> v12})

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

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

blk8:
Statements:
  (v9: core::felt252) <- 3
End:
  Goto(blk9, {v9 -> v12})

blk9:
Statements:
End:
  Return(v12)

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

//! > Tuple inside enum

//! > test_runner_name
test_create_graph(expect_diagnostics: false)

//! > function_code
fn foo(color: Option<(Color, Color)>) -> felt252 {
    match color {
        Some((Color::Red, _)) | None => 1,
        Some((_, Color::Red)) => 2,
        _ => 3,
    }
}

//! > module_code
enum Color {
    Red,
    Green,
}

//! > graph
Root: 7
7 EvaluateExpr { expr: ExprId(0), var_id: v0, next: NodeId(6) }
6 EnumMatch { matched_var: v0, variants: (NodeId(5), v1), (NodeId(0), v10)}
5 Deconstruct { input: v1, outputs: [v2, v3], next: NodeId(4) }
4 EnumMatch { matched_var: v2, variants: (NodeId(0), v4), (NodeId(3), v7)}
3 EnumMatch { matched_var: v3, variants: (NodeId(1), v8), (NodeId(2), v9)}
2 ArmExpr { expr: ExprId(3) }
1 ArmExpr { expr: ExprId(2) }
0 ArmExpr { expr: ExprId(1) }

//! > semantic_diagnostics

//! > lowering_diagnostics

//! > lowered
Parameters: v0: core::option::Option::<(test::Color, test::Color)>
blk0 (root):
Statements:
End:
  Match(match_enum(v0) {
    Option::Some(v1) => blk1,
    Option::None(v2) => blk2,
  })

blk1:
Statements:
  (v3: test::Color, v4: test::Color) <- struct_destructure(v1)
End:
  Match(match_enum(v3) {
    Color::Red(v5) => blk3,
    Color::Green(v6) => blk4,
  })

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

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

blk4:
Statements:
End:
  Match(match_enum(v4) {
    Color::Red(v7) => blk5,
    Color::Green(v8) => blk6,
  })

blk5:
Statements:
  (v10: core::felt252) <- 2
End:
  Goto(blk8, {v10 -> v12})

blk6:
Statements:
  (v9: core::felt252) <- 3
End:
  Goto(blk8, {v9 -> v12})

blk7:
Statements:
  (v11: core::felt252) <- 1
End:
  Goto(blk8, {v11 -> v12})

blk8:
Statements:
End:
  Return(v12)

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

//! > Complex enum inside tuple

//! > test_runner_name
test_create_graph(expect_diagnostics: false, skip_lowering: true)

//! > function_code
fn foo(color: (Option<Color>, Color)) -> felt252 {
    match color {
        (Some(Color::Red), Color::Red) | (Some(Color::Green), Color::Red) | (None, Color::Red) => 1,
        (_, Color::Green) => 2,
        _ => 3,
    }
}

//! > module_code
enum Color {
    Red,
    Green,
    Blue,
}

//! > graph
Root: 10
10 EvaluateExpr { expr: ExprId(0), var_id: v0, next: NodeId(9) }
9 Deconstruct { input: v0, outputs: [v1, v2], next: NodeId(8) }
8 EnumMatch { matched_var: v1, variants: (NodeId(6), v3), (NodeId(7), v16)}
7 EnumMatch { matched_var: v2, variants: (NodeId(0), v17), (NodeId(1), v18), (NodeId(2), v19)}
6 EnumMatch { matched_var: v3, variants: (NodeId(3), v4), (NodeId(4), v8), (NodeId(5), v12)}
5 EnumMatch { matched_var: v2, variants: (NodeId(2), v13), (NodeId(1), v14), (NodeId(2), v15)}
4 EnumMatch { matched_var: v2, variants: (NodeId(0), v9), (NodeId(1), v10), (NodeId(2), v11)}
3 EnumMatch { matched_var: v2, variants: (NodeId(0), v5), (NodeId(1), v6), (NodeId(2), v7)}
2 ArmExpr { expr: ExprId(3) }
1 ArmExpr { expr: ExprId(2) }
0 ArmExpr { expr: ExprId(1) }

//! > semantic_diagnostics

//! > lowering_diagnostics

//! > lowered

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

//! > Single variant enum

//! > test_runner_name
test_create_graph(expect_diagnostics: false, skip_lowering: true)

//! > function_code
// Tests that the same-node optimization is not applied when the inner value is used (for
// future match or pattern binding).
fn foo(x: Enum1) -> felt252 {
    match x {
        Enum1::A(Enum2::B(x)) => x,
    }
}

//! > module_code
enum Enum1 {
    A: Enum2,
}

enum Enum2 {
    B: felt252,
}

//! > graph
Root: 4
4 EvaluateExpr { expr: ExprId(0), var_id: v0, next: NodeId(3) }
3 EnumMatch { matched_var: v0, variants: (NodeId(2), v1)}
2 EnumMatch { matched_var: v1, variants: (NodeId(1), v2)}
1 BindVar { input: v2, output: PatternVarId(0), next: NodeId(0) }
0 ArmExpr { expr: ExprId(1) }

//! > semantic_diagnostics

//! > lowering_diagnostics

//! > lowered

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

//! > Numeric match

//! > test_runner_name
test_create_graph(expect_diagnostics: false)

//! > function_code
fn foo(x: felt252) -> felt252 {
    match x {
        2 | 4 => x,
        0 => 0,
        _ => 1,
    }
}

//! > graph
Root: 6
6 EvaluateExpr { expr: ExprId(0), var_id: v0, next: NodeId(5) }
5 EqualsLiteral { input: v0, literal: 2, true_branch: NodeId(0), false_branch: NodeId(4) }
4 EqualsLiteral { input: v0, literal: 4, true_branch: NodeId(0), false_branch: NodeId(3) }
3 EqualsLiteral { input: v0, literal: 0, true_branch: NodeId(1), false_branch: NodeId(2) }
2 ArmExpr { expr: ExprId(3) }
1 ArmExpr { expr: ExprId(2) }
0 ArmExpr { expr: ExprId(1) }

//! > semantic_diagnostics

//! > lowering_diagnostics

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

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

blk2:
Statements:
  (v4: core::felt252) <- 4
  (v5: core::felt252) <- core::Felt252Sub::sub(v0, v4)
End:
  Match(match core::felt252_is_zero(v5) {
    IsZeroResult::Zero => blk3,
    IsZeroResult::NonZero(v6) => blk4,
  })

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

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

blk5:
Statements:
  (v9: core::felt252) <- 0
End:
  Goto(blk8, {v9 -> v10})

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

blk7:
Statements:
End:
  Goto(blk8, {v0 -> v10})

blk8:
Statements:
End:
  Return(v10)

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

//! > Numeric match u16

//! > test_runner_name
test_create_graph(expect_diagnostics: false)

//! > function_code
fn foo(x: u16) -> u16 {
    match x {
        2 | 4 => x,
        _ => 1,
    }
}

//! > graph
Root: 5
5 EvaluateExpr { expr: ExprId(0), var_id: v0, next: NodeId(4) }
4 Upcast { input: v0, output: v1, next: NodeId(3) }
3 EqualsLiteral { input: v1, literal: 2, true_branch: NodeId(0), false_branch: NodeId(2) }
2 EqualsLiteral { input: v1, literal: 4, true_branch: NodeId(0), false_branch: NodeId(1) }
1 ArmExpr { expr: ExprId(2) }
0 ArmExpr { expr: ExprId(1) }

//! > semantic_diagnostics

//! > lowering_diagnostics

//! > lowered
Parameters: v0: core::integer::u16
blk0 (root):
Statements:
  (v1: core::felt252) <- core::internal::bounded_int::upcast::<core::integer::u16, core::felt252>(v0)
  (v2: core::felt252) <- 2
  (v3: core::felt252) <- core::Felt252Sub::sub(v1, v2)
End:
  Match(match core::felt252_is_zero(v3) {
    IsZeroResult::Zero => blk1,
    IsZeroResult::NonZero(v4) => blk2,
  })

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

blk2:
Statements:
  (v5: core::felt252) <- 4
  (v6: core::felt252) <- core::Felt252Sub::sub(v1, v5)
End:
  Match(match core::felt252_is_zero(v6) {
    IsZeroResult::Zero => blk3,
    IsZeroResult::NonZero(v7) => blk4,
  })

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

blk4:
Statements:
  (v8: core::integer::u16) <- 1
End:
  Goto(blk6, {v8 -> v9})

blk5:
Statements:
End:
  Goto(blk6, {v0 -> v9})

blk6:
Statements:
End:
  Return(v9)

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

//! > Optimized numeric match u16

//! > test_runner_name
test_create_graph(expect_diagnostics: false, skip_lowering: false)

//! > function_code
fn foo(x: u16) -> u16 {
    match x {
        0 | 2 | 4 | 5 | 6 | 7 => x,
        1 | 3 => 1,
        _ => 2,
    }
}

//! > graph
Root: 5
5 EvaluateExpr { expr: ExprId(0), var_id: v0, next: NodeId(4) }
4 Downcast { input: v0, output: v1, in_range: NodeId(3), out_of_range: NodeId(2) }
3 ValueMatch { matched_var: v1, nodes: [NodeId(0), NodeId(1), NodeId(0), NodeId(1), NodeId(0), NodeId(0), NodeId(0), NodeId(0)] }
2 ArmExpr { expr: ExprId(3) }
1 ArmExpr { expr: ExprId(2) }
0 ArmExpr { expr: ExprId(1) }

//! > semantic_diagnostics

//! > lowering_diagnostics

//! > lowered
Parameters: v0: core::integer::u16
blk0 (root):
Statements:
End:
  Match(match core::internal::bounded_int::downcast::<core::integer::u16, core::internal::bounded_int::BoundedInt::<0, 7>>(v0) {
    Option::Some(v1) => blk1,
    Option::None => blk2,
  })

blk1:
Statements:
End:
  Match(match_enum.(v1) {
    0(v2) => blk3,
    1(v3) => blk4,
    2(v4) => blk5,
    3(v5) => blk6,
    4(v6) => blk7,
    5(v7) => blk8,
    6(v8) => blk9,
    7(v9) => blk10,
  })

blk2:
Statements:
  (v10: core::integer::u16) <- 2
End:
  Goto(blk13, {v10 -> v12})

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

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

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

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

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

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

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

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

blk11:
Statements:
  (v11: core::integer::u16) <- 1
End:
  Goto(blk13, {v11 -> v12})

blk12:
Statements:
End:
  Goto(blk13, {v0 -> v12})

blk13:
Statements:
End:
  Return(v12)

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

//! > Optimized numeric match u16 with unoptimized literals

//! > test_runner_name
test_create_graph(expect_diagnostics: false)

//! > function_code
fn foo(x: u128) -> u128 {
    match x {
        0 | 2 | 4 | 5 | 6 | 7 | 100000000000000000000 => x,
        1 | 3 | 13 | 20 => 1,
        _ => 2,
    }
}

//! > graph
Root: 9
9 EvaluateExpr { expr: ExprId(0), var_id: v0, next: NodeId(8) }
8 Downcast { input: v0, output: v2, in_range: NodeId(7), out_of_range: NodeId(6) }
7 ValueMatch { matched_var: v2, nodes: [NodeId(0), NodeId(1), NodeId(0), NodeId(1), NodeId(0), NodeId(0), NodeId(0), NodeId(0)] }
6 Upcast { input: v0, output: v1, next: NodeId(5) }
5 EqualsLiteral { input: v1, literal: 100000000000000000000, true_branch: NodeId(0), false_branch: NodeId(4) }
4 EqualsLiteral { input: v1, literal: 13, true_branch: NodeId(1), false_branch: NodeId(3) }
3 EqualsLiteral { input: v1, literal: 20, true_branch: NodeId(1), false_branch: NodeId(2) }
2 ArmExpr { expr: ExprId(3) }
1 ArmExpr { expr: ExprId(2) }
0 ArmExpr { expr: ExprId(1) }

//! > semantic_diagnostics

//! > lowering_diagnostics

//! > lowered
Parameters: v0: core::integer::u128
blk0 (root):
Statements:
End:
  Match(match core::internal::bounded_int::downcast::<core::integer::u128, core::internal::bounded_int::BoundedInt::<0, 7>>(v0) {
    Option::Some(v1) => blk1,
    Option::None => blk2,
  })

blk1:
Statements:
End:
  Match(match_enum.(v1) {
    0(v2) => blk3,
    1(v3) => blk4,
    2(v4) => blk5,
    3(v5) => blk6,
    4(v6) => blk7,
    5(v7) => blk8,
    6(v8) => blk9,
    7(v9) => blk10,
  })

blk2:
Statements:
  (v10: core::felt252) <- core::internal::bounded_int::upcast::<core::integer::u128, core::felt252>(v0)
  (v11: core::felt252) <- 100000000000000000000
  (v12: core::felt252) <- core::Felt252Sub::sub(v10, v11)
End:
  Match(match core::felt252_is_zero(v12) {
    IsZeroResult::Zero => blk11,
    IsZeroResult::NonZero(v13) => blk12,
  })

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

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

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

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

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

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

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

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

blk11:
Statements:
End:
  Goto(blk18, {})

blk12:
Statements:
  (v14: core::felt252) <- 13
  (v15: core::felt252) <- core::Felt252Sub::sub(v10, v14)
End:
  Match(match core::felt252_is_zero(v15) {
    IsZeroResult::Zero => blk13,
    IsZeroResult::NonZero(v16) => blk14,
  })

blk13:
Statements:
End:
  Goto(blk17, {})

blk14:
Statements:
  (v17: core::felt252) <- 20
  (v18: core::felt252) <- core::Felt252Sub::sub(v10, v17)
End:
  Match(match core::felt252_is_zero(v18) {
    IsZeroResult::Zero => blk15,
    IsZeroResult::NonZero(v19) => blk16,
  })

blk15:
Statements:
End:
  Goto(blk17, {})

blk16:
Statements:
  (v20: core::integer::u128) <- 2
End:
  Goto(blk19, {v20 -> v22})

blk17:
Statements:
  (v21: core::integer::u128) <- 1
End:
  Goto(blk19, {v21 -> v22})

blk18:
Statements:
End:
  Goto(blk19, {v0 -> v22})

blk19:
Statements:
End:
  Return(v22)

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

//! > Numeric match with tuples and bindings

//! > test_runner_name
test_create_graph(expect_diagnostics: false)

//! > function_code
fn foo(x: felt252, y: felt252) -> felt252 {
    match (x, y) {
        (1, 3) => 0,
        (1, 4) | (2, 3) => 1,
        (1, 5) => 2,
        (3, _) => 3,
        (x, 0) => x,
        _ => 4,
    }
}

//! > graph
Root: 18
18 EvaluateExpr { expr: ExprId(2), var_id: v0, next: NodeId(17) }
17 Deconstruct { input: v0, outputs: [v1, v2], next: NodeId(16) }
16 EqualsLiteral { input: v1, literal: 1, true_branch: NodeId(15), false_branch: NodeId(11) }
15 EqualsLiteral { input: v2, literal: 3, true_branch: NodeId(0), false_branch: NodeId(14) }
14 EqualsLiteral { input: v2, literal: 4, true_branch: NodeId(1), false_branch: NodeId(13) }
13 EqualsLiteral { input: v2, literal: 5, true_branch: NodeId(2), false_branch: NodeId(12) }
12 EqualsLiteral { input: v2, literal: 0, true_branch: NodeId(6), false_branch: NodeId(5) }
11 EqualsLiteral { input: v1, literal: 2, true_branch: NodeId(10), false_branch: NodeId(8) }
10 EqualsLiteral { input: v2, literal: 3, true_branch: NodeId(1), false_branch: NodeId(9) }
9 EqualsLiteral { input: v2, literal: 0, true_branch: NodeId(6), false_branch: NodeId(5) }
8 EqualsLiteral { input: v1, literal: 3, true_branch: NodeId(3), false_branch: NodeId(7) }
7 EqualsLiteral { input: v2, literal: 0, true_branch: NodeId(6), false_branch: NodeId(5) }
6 BindVar { input: v1, output: PatternVarId(0), next: NodeId(4) }
5 ArmExpr { expr: ExprId(8) }
4 ArmExpr { expr: ExprId(7) }
3 ArmExpr { expr: ExprId(6) }
2 ArmExpr { expr: ExprId(5) }
1 ArmExpr { expr: ExprId(4) }
0 ArmExpr { expr: ExprId(3) }

//! > semantic_diagnostics

//! > lowering_diagnostics

//! > lowered
Parameters: v0: core::felt252, v1: core::felt252
blk0 (root):
Statements:
  (v2: (core::felt252, core::felt252)) <- struct_construct(v0, v1)
  (v3: core::felt252, v4: core::felt252) <- struct_destructure(v2)
  (v5: core::felt252) <- 1
  (v6: core::felt252) <- core::Felt252Sub::sub(v3, v5)
End:
  Match(match core::felt252_is_zero(v6) {
    IsZeroResult::Zero => blk1,
    IsZeroResult::NonZero(v7) => blk2,
  })

blk1:
Statements:
  (v8: core::felt252) <- 3
  (v9: core::felt252) <- core::Felt252Sub::sub(v4, v8)
End:
  Match(match core::felt252_is_zero(v9) {
    IsZeroResult::Zero => blk3,
    IsZeroResult::NonZero(v10) => blk4,
  })

blk2:
Statements:
  (v18: core::felt252) <- 2
  (v19: core::felt252) <- core::Felt252Sub::sub(v3, v18)
End:
  Match(match core::felt252_is_zero(v19) {
    IsZeroResult::Zero => blk11,
    IsZeroResult::NonZero(v20) => blk12,
  })

blk3:
Statements:
  (v33: core::felt252) <- 0
End:
  Goto(blk24, {v33 -> v34})

blk4:
Statements:
  (v11: core::felt252) <- 4
  (v12: core::felt252) <- core::Felt252Sub::sub(v4, v11)
End:
  Match(match core::felt252_is_zero(v12) {
    IsZeroResult::Zero => blk5,
    IsZeroResult::NonZero(v13) => blk6,
  })

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

blk6:
Statements:
  (v14: core::felt252) <- 5
  (v15: core::felt252) <- core::Felt252Sub::sub(v4, v14)
End:
  Match(match core::felt252_is_zero(v15) {
    IsZeroResult::Zero => blk7,
    IsZeroResult::NonZero(v16) => blk8,
  })

blk7:
Statements:
  (v31: core::felt252) <- 2
End:
  Goto(blk24, {v31 -> v34})

blk8:
Statements:
End:
  Match(match core::felt252_is_zero(v4) {
    IsZeroResult::Zero => blk9,
    IsZeroResult::NonZero(v17) => blk10,
  })

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

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

blk11:
Statements:
  (v21: core::felt252) <- 3
  (v22: core::felt252) <- core::Felt252Sub::sub(v4, v21)
End:
  Match(match core::felt252_is_zero(v22) {
    IsZeroResult::Zero => blk13,
    IsZeroResult::NonZero(v23) => blk14,
  })

blk12:
Statements:
  (v25: core::felt252) <- 3
  (v26: core::felt252) <- core::Felt252Sub::sub(v3, v25)
End:
  Match(match core::felt252_is_zero(v26) {
    IsZeroResult::Zero => blk17,
    IsZeroResult::NonZero(v27) => blk18,
  })

blk13:
Statements:
End:
  Goto(blk23, {})

blk14:
Statements:
End:
  Match(match core::felt252_is_zero(v4) {
    IsZeroResult::Zero => blk15,
    IsZeroResult::NonZero(v24) => blk16,
  })

blk15:
Statements:
End:
  Goto(blk21, {})

blk16:
Statements:
End:
  Goto(blk22, {})

blk17:
Statements:
  (v30: core::felt252) <- 3
End:
  Goto(blk24, {v30 -> v34})

blk18:
Statements:
End:
  Match(match core::felt252_is_zero(v4) {
    IsZeroResult::Zero => blk19,
    IsZeroResult::NonZero(v28) => blk20,
  })

blk19:
Statements:
End:
  Goto(blk21, {})

blk20:
Statements:
End:
  Goto(blk22, {})

blk21:
Statements:
End:
  Goto(blk24, {v3 -> v34})

blk22:
Statements:
  (v29: core::felt252) <- 4
End:
  Goto(blk24, {v29 -> v34})

blk23:
Statements:
  (v32: core::felt252) <- 1
End:
  Goto(blk24, {v32 -> v34})

blk24:
Statements:
End:
  Return(v34)

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

//! > Test a non-branching graph

//! > test_runner_name
test_create_graph(expect_diagnostics: false)

//! > function_code
fn foo(x: Option<felt252>) -> felt252 {
    match x {
        _ => 0,
    }
}

//! > graph
Root: 1
1 EvaluateExpr { expr: ExprId(0), var_id: v0, next: NodeId(0) }
0 ArmExpr { expr: ExprId(1) }

//! > semantic_diagnostics

//! > lowering_diagnostics

//! > lowered
Parameters: v0: core::option::Option::<core::felt252>
blk0 (root):
Statements:
  (v1: core::felt252) <- 0
End:
  Return(v1)

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

//! > Tuples with pattern binding inside of enums

//! > test_runner_name
test_create_graph(expect_diagnostics: false)

//! > function_code
fn foo(color: @(Color, Color)) -> felt252 {
    match color {
        // x can be bound to different tuple items.
        (Color::Red(x), _) | (_, Color::Red(x)) => *x,
        _ => 0,
    }
}

//! > module_code
enum Color {
    Red: felt252,
    Green,
    Blue,
}

//! > graph
Root: 7
7 EvaluateExpr { expr: ExprId(0), var_id: v0, next: NodeId(6) }
6 Deconstruct { input: v0, outputs: [v1, v2], next: NodeId(5) }
5 EnumMatch { matched_var: v1, variants: (NodeId(2), v3), (NodeId(4), v7), (NodeId(4), v11)}
4 EnumMatch { matched_var: v2, variants: (NodeId(3), v8), (NodeId(1), v9), (NodeId(1), v10)}
3 BindVar { input: v8, output: PatternVarId(2), next: NodeId(0) }
2 BindVar { input: v3, output: PatternVarId(0), next: NodeId(0) }
1 ArmExpr { expr: ExprId(3) }
0 ArmExpr { expr: ExprId(2) }

//! > semantic_diagnostics

//! > lowering_diagnostics

//! > lowered
Parameters: v0: @(test::Color, test::Color)
blk0 (root):
Statements:
  (v1: @test::Color, v2: @test::Color) <- struct_destructure(v0)
End:
  Match(match_enum(v1) {
    Color::Red(v3) => blk1,
    Color::Green(v4) => blk2,
    Color::Blue(v5) => blk3,
  })

blk1:
Statements:
End:
  Goto(blk9, {v3 -> v10})

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

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

blk4:
Statements:
End:
  Match(match_enum(v2) {
    Color::Red(v6) => blk5,
    Color::Green(v7) => blk6,
    Color::Blue(v8) => blk7,
  })

blk5:
Statements:
End:
  Goto(blk9, {v6 -> v10})

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

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

blk8:
Statements:
  (v9: core::felt252) <- 0
End:
  Goto(blk10, {v9 -> v12})

blk9:
Statements:
  (v11: core::felt252) <- desnap(v10)
End:
  Goto(blk10, {v11 -> v12})

blk10:
Statements:
End:
  Return(v12)

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

//! > Tuples with pattern binding outside of enums

//! > test_runner_name
test_create_graph(expect_diagnostics: false)

//! > function_code
fn foo(color: (Color, Color)) -> Color {
    match color {
        // x can be bound to different tuple items.
        (Color::Red, x) | (x, Color::Red) => x,
        _ => Color::Green,
    }
}

//! > module_code
enum Color {
    Red,
    Green,
    Blue,
}

//! > graph
Root: 7
7 EvaluateExpr { expr: ExprId(0), var_id: v0, next: NodeId(6) }
6 Deconstruct { input: v0, outputs: [v1, v2], next: NodeId(5) }
5 EnumMatch { matched_var: v1, variants: (NodeId(2), v3), (NodeId(4), v7), (NodeId(4), v11)}
4 EnumMatch { matched_var: v2, variants: (NodeId(3), v8), (NodeId(1), v9), (NodeId(1), v10)}
3 BindVar { input: v1, output: PatternVarId(0), next: NodeId(0) }
2 BindVar { input: v2, output: PatternVarId(1), next: NodeId(0) }
1 ArmExpr { expr: ExprId(3) }
0 ArmExpr { expr: ExprId(1) }

//! > semantic_diagnostics

//! > lowering_diagnostics

//! > lowered
Parameters: v0: (test::Color, test::Color)
blk0 (root):
Statements:
  (v1: test::Color, v2: test::Color) <- struct_destructure(v0)
End:
  Match(match_enum(v1) {
    Color::Red(v3) => blk1,
    Color::Green(v4) => blk2,
    Color::Blue(v5) => blk3,
  })

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

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

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

blk4:
Statements:
End:
  Match(match_enum(v2) {
    Color::Red(v6) => blk5,
    Color::Green(v7) => blk6,
    Color::Blue(v8) => blk7,
  })

blk5:
Statements:
End:
  Goto(blk9, {v1 -> v11})

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

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

blk8:
Statements:
  (v9: ()) <- struct_construct()
  (v10: test::Color) <- Color::Green(v9)
End:
  Goto(blk10, {v10 -> v12})

blk9:
Statements:
End:
  Goto(blk10, {v11 -> v12})

blk10:
Statements:
End:
  Return(v12)

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

//! > Incomplete match

//! > test_runner_name
test_create_graph(expect_diagnostics: true)

//! > function_code
fn foo(x: MyStruct) -> felt252 {
    match x {
        MyStruct { a: Some(Some(_)), .. } => 1,
        MyStruct { b: (None, _, _), .. } => 1,
    }
}

//! > module_code
struct MyStruct {
    a: Option<Option<felt252>>,
    b: (Option<felt252>, felt252, felt252),
}

//! > graph
Root: 9
9 EvaluateExpr { expr: ExprId(0), var_id: v0, next: NodeId(8) }
8 Deconstruct { input: v0, outputs: [v1, v2], next: NodeId(7) }
7 EnumMatch { matched_var: v1, variants: (NodeId(6), v3), (NodeId(5), v16)}
6 EnumMatch { matched_var: v3, variants: (NodeId(2), v4), (NodeId(5), v10)}
5 Deconstruct { input: v2, outputs: [v11, v12, v13], next: NodeId(4) }
4 EnumMatch { matched_var: v11, variants: (NodeId(3), v14), (NodeId(1), v15)}
3 Missing
2 Deconstruct { input: v2, outputs: [v5, v6, v7], next: NodeId(0) }
1 ArmExpr { expr: ExprId(2) }
0 ArmExpr { expr: ExprId(1) }

//! > semantic_diagnostics

//! > lowering_diagnostics
error[E3004]: Match is non-exhaustive: `MyStruct{a: Some(None(_)), b: (Some(_), _, _)}` not covered.
 --> lib.cairo:6:5-9:5
      match x {
 _____^
| ...
|     }
|_____^

//! > lowered
Parameters: v0: test::MyStruct

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

//! > Unsupported pattern

//! > test_runner_name
test_create_graph(expect_diagnostics: true)

//! > function_code
fn foo(x: (Option<(felt252, felt252)>, felt252)) -> felt252 {
    match x {
        (_, ()) | ((), _) | (Some(None), _) | _ => 0,
    }
}

//! > graph
Root: 7
7 EvaluateExpr { expr: ExprId(0), var_id: v0, next: NodeId(6) }
6 Deconstruct { input: v0, outputs: [v1, v2], next: NodeId(5) }
5 EnumMatch { matched_var: v1, variants: (NodeId(3), v3), (NodeId(4), v6)}
4 Missing
3 Deconstruct { input: v3, outputs: [v4, v5], next: NodeId(2) }
2 Missing
1 Missing
0 ArmExpr { expr: ExprId(1) }

//! > semantic_diagnostics
error[E2103]: Mismatched types: pattern cannot match against type "core::felt252".
 --> lib.cairo:3:13
        (_, ()) | ((), _) | (Some(None), _) | _ => 0,
            ^^

error[E2103]: Mismatched types: pattern cannot match against type "core::option::Option::<(core::felt252, core::felt252)>".
 --> lib.cairo:3:20
        (_, ()) | ((), _) | (Some(None), _) | _ => 0,
                   ^^

error[E2103]: Mismatched types: pattern cannot match against type "(core::felt252, core::felt252)".
 --> lib.cairo:3:35
        (_, ()) | ((), _) | (Some(None), _) | _ => 0,
                                  ^^^^

//! > lowering_diagnostics
error[E3007]: Unexpected error has occurred, Please submit a full bug report. See https://github.com/starkware-libs/cairo/issues/new/choose for instructions.
 --> lib.cairo:3:20
        (_, ()) | ((), _) | (Some(None), _) | _ => 0,
                   ^^

error[E3007]: Unexpected error has occurred, Please submit a full bug report. See https://github.com/starkware-libs/cairo/issues/new/choose for instructions.
 --> lib.cairo:3:35
        (_, ()) | ((), _) | (Some(None), _) | _ => 0,
                                  ^^^^

error[E3007]: Unexpected error has occurred, Please submit a full bug report. See https://github.com/starkware-libs/cairo/issues/new/choose for instructions.
 --> lib.cairo:3:13
        (_, ()) | ((), _) | (Some(None), _) | _ => 0,
            ^^

//! > lowered
Parameters: v0: (core::option::Option::<(core::felt252, core::felt252)>, core::felt252)

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

//! > Match with numeric literal out of range

//! > test_runner_name
test_create_graph(expect_diagnostics: true, skip_lowering: true)

//! > function_code
fn foo(a: u8) -> bool {
    match a {
        255 | 256 | 257 => false,
        _ => true,
    }
}

//! > graph
Root: 4
4 EvaluateExpr { expr: ExprId(0), var_id: v0, next: NodeId(3) }
3 Upcast { input: v0, output: v1, next: NodeId(2) }
2 EqualsLiteral { input: v1, literal: 255, true_branch: NodeId(0), false_branch: NodeId(1) }
1 ArmExpr { expr: ExprId(4) }
0 ArmExpr { expr: ExprId(2) }

//! > semantic_diagnostics

//! > lowering_diagnostics
error[E3009]: The value does not fit within the range of type core::integer::u8.
 --> lib.cairo:3:15
        255 | 256 | 257 => false,
              ^^^

error[E3009]: The value does not fit within the range of type core::integer::u8.
 --> lib.cairo:3:21
        255 | 256 | 257 => false,
                    ^^^

//! > lowered

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

//! > Match with no arms

//! > test_runner_name
test_create_graph(expect_diagnostics: true)

//! > function_code
fn foo(x: Option<felt252>) -> felt252 {
    match x {}
}

//! > graph
Root: 1
1 EvaluateExpr { expr: ExprId(0), var_id: v0, next: NodeId(0) }
0 Missing

//! > semantic_diagnostics

//! > lowering_diagnostics
error[E3004]: Match is non-exhaustive: `_` not covered.
 --> lib.cairo:2:5
    match x {}
    ^^^^^^^^^^

//! > lowered
Parameters: v0: core::option::Option::<core::felt252>

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

//! > Match on never type

//! > test_runner_name
test_create_graph(expect_diagnostics: false)

//! > function_code
fn foo(x: never) -> felt252 {
    match x {}
}

//! > graph
Root: 1
1 EvaluateExpr { expr: ExprId(0), var_id: v0, next: NodeId(0) }
0 EnumMatch { matched_var: v0, variants: }

//! > semantic_diagnostics

//! > lowering_diagnostics

//! > lowered
Parameters: v0: core::never
blk0 (root):
Statements:
End:
  Match(match_enum(v0) {
  })

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

//! > Match on never type wrapped in single-variant enum

//! > test_runner_name
test_create_graph(expect_diagnostics: true)

//! > function_code
fn foo(x: NeverEnum) -> felt252 {
    match x {}
}

//! > module_code
enum NeverEnum {
    Never: never,
}

//! > graph
Root: 1
1 EvaluateExpr { expr: ExprId(0), var_id: v0, next: NodeId(0) }
0 Missing

//! > semantic_diagnostics

//! > lowering_diagnostics
error[E3004]: Match is non-exhaustive: `_` not covered.
 --> lib.cairo:5:5
    match x {}
    ^^^^^^^^^^

//! > lowered
Parameters: v0: test::NeverEnum

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

//! > Structs

//! > test_runner_name
test_create_graph(expect_diagnostics: false)

//! > function_code
fn foo(x: MyStruct) -> felt252 {
    match x {
        MyStruct { b: (None, 0), a: Some(x), .. } => x,
        _ => 0,
    }
}

//! > module_code
struct MyStruct {
    a: Option<felt252>,
    b: (Option<felt252>, felt252),
    c: Option<felt252>,
}

//! > graph
Root: 8
8 EvaluateExpr { expr: ExprId(0), var_id: v0, next: NodeId(7) }
7 Deconstruct { input: v0, outputs: [v1, v2, v3], next: NodeId(6) }
6 EnumMatch { matched_var: v1, variants: (NodeId(5), v4), (NodeId(1), v9)}
5 Deconstruct { input: v2, outputs: [v5, v6], next: NodeId(4) }
4 EnumMatch { matched_var: v5, variants: (NodeId(1), v7), (NodeId(3), v8)}
3 EqualsLiteral { input: v6, literal: 0, true_branch: NodeId(2), false_branch: NodeId(1) }
2 BindVar { input: v4, output: PatternVarId(0), next: NodeId(0) }
1 ArmExpr { expr: ExprId(2) }
0 ArmExpr { expr: ExprId(1) }

//! > semantic_diagnostics

//! > lowering_diagnostics

//! > lowered
Parameters: v0: test::MyStruct
blk0 (root):
Statements:
  (v1: core::option::Option::<core::felt252>, v2: (core::option::Option::<core::felt252>, core::felt252), v3: core::option::Option::<core::felt252>) <- struct_destructure(v0)
End:
  Match(match_enum(v1) {
    Option::Some(v4) => blk1,
    Option::None(v5) => blk2,
  })

blk1:
Statements:
  (v6: core::option::Option::<core::felt252>, v7: core::felt252) <- struct_destructure(v2)
End:
  Match(match_enum(v6) {
    Option::Some(v8) => blk3,
    Option::None(v9) => blk4,
  })

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

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

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

blk5:
Statements:
End:
  Goto(blk8, {v4 -> v12})

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

blk7:
Statements:
  (v11: core::felt252) <- 0
End:
  Goto(blk8, {v11 -> v12})

blk8:
Statements:
End:
  Return(v12)

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

//! > Optimized extern match

//! > test_runner_name
test_create_graph(expect_diagnostics: false)

//! > function_code
fn foo(mut x: felt252) -> felt252 {
    match bar(ref x) {
        MyEnum::Pair1(a) => {
            let (b, _c) = a;
            b.into() + x
        },
        MyEnum::Pair2((_, c)) => { c.into() + x },
        MyEnum::Struct(MyStruct { c, .. }) => { c.into() + x },
        MyEnum::Single(a) => { a.into() + x },
        MyEnum::Opt(Some(a)) => { a.into() + x },
        _ => x + 1,
    }
}

//! > module_code
enum MyEnum {
    Single: u8,
    Pair1: (u8, u8),
    Pair2: (u8, u8),
    Pair3: (u8, u8),
    Struct: MyStruct,
    Opt: Option<u8>,
}

struct MyStruct {
    b: u8,
    c: u8,
}

extern fn bar(ref x: felt252) -> MyEnum nopanic;

//! > graph
Root: 15
15 EvaluateExpr { expr: ExprId(1), var_id: v0, next: NodeId(14) }
14 EnumMatch { matched_var: v0, variants: (NodeId(6), v1), (NodeId(7), v2), (NodeId(9), v3), (NodeId(5), v6), (NodeId(11), v7), (NodeId(13), v10)}
13 EnumMatch { matched_var: v10, variants: (NodeId(12), v11), (NodeId(5), v12)}
12 BindVar { input: v11, output: PatternVarId(4), next: NodeId(4) }
11 Deconstruct { input: v7, outputs: [v8, v9], next: NodeId(10) }
10 BindVar { input: v9, output: PatternVarId(3), next: NodeId(2) }
9 Deconstruct { input: v3, outputs: [v4, v5], next: NodeId(8) }
8 BindVar { input: v5, output: PatternVarId(2), next: NodeId(1) }
7 BindVar { input: v2, output: PatternVarId(1), next: NodeId(0) }
6 BindVar { input: v1, output: PatternVarId(0), next: NodeId(3) }
5 ArmExpr { expr: ExprId(30) }
4 ArmExpr { expr: ExprId(27) }
3 ArmExpr { expr: ExprId(22) }
2 ArmExpr { expr: ExprId(17) }
1 ArmExpr { expr: ExprId(12) }
0 ArmExpr { expr: ExprId(7) }

//! > semantic_diagnostics

//! > lowering_diagnostics

//! > lowered
Parameters: v0: core::felt252
blk0 (root):
Statements:
End:
  Match(match test::bar(v0) {
    MyEnum::Single(v1, v2) => blk1,
    MyEnum::Pair1(v3, v4, v5) => blk2,
    MyEnum::Pair2(v7, v8, v9) => blk3,
    MyEnum::Pair3(v11, v12, v13) => blk4,
    MyEnum::Struct(v15, v16) => blk5,
    MyEnum::Opt(v17, v18) => blk6,
  })

blk1:
Statements:
  (v30: core::felt252) <- core::integer::U8IntoFelt252::into(v2)
  (v31: core::felt252) <- core::Felt252Add::add(v30, v1)
End:
  Goto(blk10, {v1 -> v41, v31 -> v40})

blk2:
Statements:
  (v6: (core::integer::u8, core::integer::u8)) <- struct_construct(v4, v5)
  (v36: core::integer::u8, v37: core::integer::u8) <- struct_destructure(v6)
  (v38: core::felt252) <- core::integer::U8IntoFelt252::into(v36)
  (v39: core::felt252) <- core::Felt252Add::add(v38, v3)
End:
  Goto(blk10, {v3 -> v41, v39 -> v40})

blk3:
Statements:
  (v10: (core::integer::u8, core::integer::u8)) <- struct_construct(v8, v9)
  (v23: core::integer::u8, v24: core::integer::u8) <- struct_destructure(v10)
  (v34: core::felt252) <- core::integer::U8IntoFelt252::into(v24)
  (v35: core::felt252) <- core::Felt252Add::add(v34, v7)
End:
  Goto(blk10, {v7 -> v41, v35 -> v40})

blk4:
Statements:
  (v14: (core::integer::u8, core::integer::u8)) <- struct_construct(v12, v13)
End:
  Goto(blk9, {v11 -> v25})

blk5:
Statements:
  (v21: core::integer::u8, v22: core::integer::u8) <- struct_destructure(v16)
  (v32: core::felt252) <- core::integer::U8IntoFelt252::into(v22)
  (v33: core::felt252) <- core::Felt252Add::add(v32, v15)
End:
  Goto(blk10, {v15 -> v41, v33 -> v40})

blk6:
Statements:
End:
  Match(match_enum(v18) {
    Option::Some(v19) => blk7,
    Option::None(v20) => blk8,
  })

blk7:
Statements:
  (v28: core::felt252) <- core::integer::U8IntoFelt252::into(v19)
  (v29: core::felt252) <- core::Felt252Add::add(v28, v17)
End:
  Goto(blk10, {v17 -> v41, v29 -> v40})

blk8:
Statements:
End:
  Goto(blk9, {v17 -> v25})

blk9:
Statements:
  (v26: core::felt252) <- 1
  (v27: core::felt252) <- core::Felt252Add::add(v25, v26)
End:
  Goto(blk10, {v25 -> v41, v27 -> v40})

blk10:
Statements:
End:
  Return(v40)

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

//! > No extern match optimization if the value is bound.

//! > test_runner_name
test_create_graph(expect_diagnostics: false)

//! > function_code
fn foo() -> felt252 {
    match bar() {
        Some(a) => a,
        _x => 0,
    }
}

//! > module_code
extern fn bar() -> Option<felt252> nopanic;

//! > graph
Root: 5
5 EvaluateExpr { expr: ExprId(0), var_id: v0, next: NodeId(4) }
4 EnumMatch { matched_var: v0, variants: (NodeId(2), v1), (NodeId(3), v2)}
3 BindVar { input: v0, output: PatternVarId(0), next: NodeId(1) }
2 BindVar { input: v1, output: PatternVarId(1), next: NodeId(0) }
1 ArmExpr { expr: ExprId(2) }
0 ArmExpr { expr: ExprId(1) }

//! > semantic_diagnostics

//! > lowering_diagnostics

//! > lowered
Parameters:
blk0 (root):
Statements:
End:
  Match(match test::bar() {
    Option::Some(v0) => blk1,
    Option::None => blk2,
  })

blk1:
Statements:
  (v1: core::option::Option::<core::felt252>) <- Option::Some(v0)
End:
  Goto(blk3, {v1 -> v4})

blk2:
Statements:
  (v2: ()) <- struct_construct()
  (v3: core::option::Option::<core::felt252>) <- Option::None(v2)
End:
  Goto(blk3, {v3 -> v4})

blk3:
Statements:
End:
  Match(match_enum(v4) {
    Option::Some(v5) => blk4,
    Option::None(v6) => blk5,
  })

blk4:
Statements:
End:
  Goto(blk6, {v5 -> v8})

blk5:
Statements:
  (v7: core::felt252) <- 0
End:
  Goto(blk6, {v7 -> v8})

blk6:
Statements:
End:
  Return(v8)

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

//! > No extern match optimization when the match is skipped.

//! > test_runner_name
test_create_graph(expect_diagnostics: false)

//! > function_code
fn foo() -> felt252 {
    match bar() {
        _ => 0,
    }
}

//! > module_code
extern fn bar() -> Option<felt252> nopanic;

//! > graph
Root: 1
1 EvaluateExpr { expr: ExprId(0), var_id: v0, next: NodeId(0) }
0 ArmExpr { expr: ExprId(1) }

//! > semantic_diagnostics

//! > lowering_diagnostics

//! > lowered
Parameters:
blk0 (root):
Statements:
End:
  Match(match test::bar() {
    Option::Some(v0) => blk1,
    Option::None => blk2,
  })

blk1:
Statements:
  (v1: core::option::Option::<core::felt252>) <- Option::Some(v0)
End:
  Goto(blk3, {v1 -> v4})

blk2:
Statements:
  (v2: ()) <- struct_construct()
  (v3: core::option::Option::<core::felt252>) <- Option::None(v2)
End:
  Goto(blk3, {v3 -> v4})

blk3:
Statements:
  (v5: core::felt252) <- 0
End:
  Return(v5)

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

//! > Match u256

//! > test_runner_name
test_create_graph(expect_diagnostics: true, skip_lowering: true)

//! > function_code
fn foo(x: u256) -> felt252 {
    match x {
        0 => 1,
        1 => 2,
        0x300000000000000000000000000000004 => 3,
        0x500000000000000000000000000000004 => 4,
        u256 { low: 4, high: _ } => 5,
        _ => 6,
        // Value out of range.
        0x10000000000000000000000000000000000000000000000000000000000000000 => 7,
    }
}

//! > graph
Root: 19
19 EvaluateExpr { expr: ExprId(0), var_id: v0, next: NodeId(18) }
18 Deconstruct { input: v0, outputs: [v1, v2], next: NodeId(17) }
17 Upcast { input: v1, output: v3, next: NodeId(16) }
16 EqualsLiteral { input: v3, literal: 0, true_branch: NodeId(15), false_branch: NodeId(13) }
15 Upcast { input: v2, output: v6, next: NodeId(14) }
14 EqualsLiteral { input: v6, literal: 0, true_branch: NodeId(0), false_branch: NodeId(5) }
13 EqualsLiteral { input: v3, literal: 1, true_branch: NodeId(12), false_branch: NodeId(10) }
12 Upcast { input: v2, output: v5, next: NodeId(11) }
11 EqualsLiteral { input: v5, literal: 0, true_branch: NodeId(1), false_branch: NodeId(5) }
10 EqualsLiteral { input: v3, literal: 4, true_branch: NodeId(9), false_branch: NodeId(5) }
9 Upcast { input: v2, output: v4, next: NodeId(8) }
8 EqualsLiteral { input: v4, literal: 3, true_branch: NodeId(2), false_branch: NodeId(7) }
7 EqualsLiteral { input: v4, literal: 5, true_branch: NodeId(3), false_branch: NodeId(4) }
6 ArmExpr { expr: ExprId(7) }
5 ArmExpr { expr: ExprId(6) }
4 ArmExpr { expr: ExprId(5) }
3 ArmExpr { expr: ExprId(4) }
2 ArmExpr { expr: ExprId(3) }
1 ArmExpr { expr: ExprId(2) }
0 ArmExpr { expr: ExprId(1) }

//! > semantic_diagnostics

//! > lowering_diagnostics
error[E3009]: The value does not fit within the range of type core::integer::u256.
 --> lib.cairo:10:9
        0x10000000000000000000000000000000000000000000000000000000000000000 => 7,
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

//! > lowered

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

//! > Match u256 with optimized numeric match on low

//! > test_runner_name
test_create_graph(expect_diagnostics: false, skip_lowering: true)

//! > function_code
// TODO(lior): Consider optimizing to avoid the multiple `EqualsLiteral` nodes.
fn foo(x: u256) -> u256 {
    match x {
        0 | 2 | 4 | 5 | 6 | 7 => x,
        1 | 3 => 1,
        _ => 2,
    }
}

//! > graph
Root: 22
22 EvaluateExpr { expr: ExprId(0), var_id: v0, next: NodeId(21) }
21 Deconstruct { input: v0, outputs: [v1, v2], next: NodeId(20) }
20 Downcast { input: v1, output: v3, in_range: NodeId(19), out_of_range: NodeId(2) }
19 ValueMatch { matched_var: v3, nodes: [NodeId(4), NodeId(6), NodeId(8), NodeId(10), NodeId(12), NodeId(14), NodeId(16), NodeId(18)] }
18 Upcast { input: v2, output: v11, next: NodeId(17) }
17 EqualsLiteral { input: v11, literal: 0, true_branch: NodeId(0), false_branch: NodeId(2) }
16 Upcast { input: v2, output: v10, next: NodeId(15) }
15 EqualsLiteral { input: v10, literal: 0, true_branch: NodeId(0), false_branch: NodeId(2) }
14 Upcast { input: v2, output: v9, next: NodeId(13) }
13 EqualsLiteral { input: v9, literal: 0, true_branch: NodeId(0), false_branch: NodeId(2) }
12 Upcast { input: v2, output: v8, next: NodeId(11) }
11 EqualsLiteral { input: v8, literal: 0, true_branch: NodeId(0), false_branch: NodeId(2) }
10 Upcast { input: v2, output: v7, next: NodeId(9) }
9 EqualsLiteral { input: v7, literal: 0, true_branch: NodeId(1), false_branch: NodeId(2) }
8 Upcast { input: v2, output: v6, next: NodeId(7) }
7 EqualsLiteral { input: v6, literal: 0, true_branch: NodeId(0), false_branch: NodeId(2) }
6 Upcast { input: v2, output: v5, next: NodeId(5) }
5 EqualsLiteral { input: v5, literal: 0, true_branch: NodeId(1), false_branch: NodeId(2) }
4 Upcast { input: v2, output: v4, next: NodeId(3) }
3 EqualsLiteral { input: v4, literal: 0, true_branch: NodeId(0), false_branch: NodeId(2) }
2 ArmExpr { expr: ExprId(3) }
1 ArmExpr { expr: ExprId(2) }
0 ArmExpr { expr: ExprId(1) }

//! > semantic_diagnostics

//! > lowering_diagnostics

//! > lowered

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

//! > Match u256 with optimized numeric match on high

//! > test_runner_name
test_create_graph(expect_diagnostics: false, skip_lowering: true)

//! > function_code
fn foo(x: u256) -> u256 {
    match x {
        0x000000000000000000000000000000004 | 0x200000000000000000000000000000004 |
        0x400000000000000000000000000000004 | 0x500000000000000000000000000000004 |
        0x600000000000000000000000000000004 | 0x700000000000000000000000000000004 => x,
        0x100000000000000000000000000000004 | 0x300000000000000000000000000000004 => 1,
        _ => 2,
    }
}

//! > graph
Root: 8
8 EvaluateExpr { expr: ExprId(0), var_id: v0, next: NodeId(7) }
7 Deconstruct { input: v0, outputs: [v1, v2], next: NodeId(6) }
6 Upcast { input: v1, output: v3, next: NodeId(5) }
5 EqualsLiteral { input: v3, literal: 4, true_branch: NodeId(4), false_branch: NodeId(2) }
4 Downcast { input: v2, output: v4, in_range: NodeId(3), out_of_range: NodeId(2) }
3 ValueMatch { matched_var: v4, nodes: [NodeId(0), NodeId(1), NodeId(0), NodeId(1), NodeId(0), NodeId(0), NodeId(0), NodeId(0)] }
2 ArmExpr { expr: ExprId(3) }
1 ArmExpr { expr: ExprId(2) }
0 ArmExpr { expr: ExprId(1) }

//! > semantic_diagnostics

//! > lowering_diagnostics

//! > lowered

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

//! > Boxed enum recursive match with snapshots

//! > test_runner_name
test_create_graph(expect_diagnostics: false)

//! > function_code
fn foo(x: (@@Box<@@@Outer>, @@@Inner)) -> (@@Box<@@@Leaf>,) {
    match x {
        (Outer::Wrap(Inner::Next(leaf)), Inner::Next(_)) => (leaf,),
        _ => (@@BoxTrait::new(@@@Leaf::A(5)),),
    }
}

//! > module_code
enum Outer {
    Wrap: Inner,
    Other: felt252,
}

enum Inner {
    Next: Leaf,
}

enum Leaf {
    A: felt252,
}

//! > graph
Root: 6
6 EvaluateExpr { expr: ExprId(0), var_id: v0, next: NodeId(5) }
5 Deconstruct { input: v0, outputs: [v1, v2], next: NodeId(4) }
4 EnumMatch { matched_var: v1, variants: (NodeId(3), v3), (NodeId(1), v6)}
3 EnumMatch { matched_var: v3, variants: (NodeId(2), v4)}
2 BindVar { input: v4, output: PatternVarId(0), next: NodeId(0) }
1 ArmExpr { expr: ExprId(11) }
0 ArmExpr { expr: ExprId(2) }

//! > semantic_diagnostics

//! > lowering_diagnostics

//! > lowered
Parameters: v0: (@@core::box::Box::<@@@test::Outer>, @@@test::Inner)
blk0 (root):
Statements:
  (v1: @@core::box::Box::<@@@test::Outer>, v2: @@@test::Inner) <- struct_destructure(v0)
End:
  Match(match_enum(v1) {
    Outer::Wrap(v3) => blk1,
    Outer::Other(v4) => blk2,
  })

blk1:
Statements:
End:
  Match(match_enum(v3) {
    Inner::Next(v5) => blk3,
  })

blk2:
Statements:
  (v6: core::felt252) <- 5
  (v7: test::Leaf) <- Leaf::A(v6)
  (v8: test::Leaf, v9: @test::Leaf) <- snapshot(v7)
  (v10: @test::Leaf, v11: @@test::Leaf) <- snapshot(v9)
  (v12: @@test::Leaf, v13: @@@test::Leaf) <- snapshot(v11)
  (v14: core::box::Box::<@@@test::Leaf>) <- core::box::BoxImpl::<@@@test::Leaf>::new(v13)
  (v15: core::box::Box::<@@@test::Leaf>, v16: @core::box::Box::<@@@test::Leaf>) <- snapshot(v14)
  (v17: @core::box::Box::<@@@test::Leaf>, v18: @@core::box::Box::<@@@test::Leaf>) <- snapshot(v16)
  (v19: (@@core::box::Box::<@@@test::Leaf>,)) <- struct_construct(v18)
End:
  Goto(blk4, {v19 -> v21})

blk3:
Statements:
  (v20: (@@core::box::Box::<@@@test::Leaf>,)) <- struct_construct(v5)
End:
  Goto(blk4, {v20 -> v21})

blk4:
Statements:
End:
  Return(v21)

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

//! > Boxed enum Never type

//! > test_runner_name
test_create_graph(expect_diagnostics: false)

//! > function_code
fn foo(x: Box<Never>) -> felt252 {
    match x {}
}

//! > module_code
enum Never {}

//! > graph
Root: 1
1 EvaluateExpr { expr: ExprId(0), var_id: v0, next: NodeId(0) }
0 EnumMatch { matched_var: v0, variants: }

//! > semantic_diagnostics

//! > lowering_diagnostics

//! > lowered
Parameters: v0: core::box::Box::<test::Never>
blk0 (root):
Statements:
End:
  Match(match_enum(v0) {
  })

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

//! > Boxed struct deconstruct to enum match

//! > test_runner_name
test_create_graph(expect_diagnostics: false)

//! > function_code
fn foo(x: Box<(MyEnum, MyEnum)>) -> Box<felt252> {
    match x {
        (MyEnum::Variant1(x), MyEnum::Variant1(_)) => x,
        (MyEnum::Variant2(x), MyEnum::Variant2(_)) => x,
        _ => BoxTrait::new(2),
    }
}

//! > module_code
enum MyEnum {
    Variant1: felt252,
    Variant2: felt252,
}

//! > graph
Root: 9
9 EvaluateExpr { expr: ExprId(0), var_id: v0, next: NodeId(8) }
8 Deconstruct { input: v0, outputs: [v1, v2], next: NodeId(7) }
7 EnumMatch { matched_var: v1, variants: (NodeId(4), v3), (NodeId(6), v6)}
6 EnumMatch { matched_var: v2, variants: (NodeId(2), v7), (NodeId(5), v8)}
5 BindVar { input: v6, output: PatternVarId(1), next: NodeId(1) }
4 EnumMatch { matched_var: v2, variants: (NodeId(3), v4), (NodeId(2), v5)}
3 BindVar { input: v3, output: PatternVarId(0), next: NodeId(0) }
2 ArmExpr { expr: ExprId(4) }
1 ArmExpr { expr: ExprId(2) }
0 ArmExpr { expr: ExprId(1) }

//! > semantic_diagnostics

//! > lowering_diagnostics

//! > lowered
Parameters: v0: core::box::Box::<(test::MyEnum, test::MyEnum)>
blk0 (root):
Statements:
  (v1: core::box::Box::<test::MyEnum>, v2: core::box::Box::<test::MyEnum>) <- struct_destructure(v0)
End:
  Match(match_enum(v1) {
    MyEnum::Variant1(v3) => blk1,
    MyEnum::Variant2(v4) => blk2,
  })

blk1:
Statements:
End:
  Match(match_enum(v2) {
    MyEnum::Variant1(v7) => blk5,
    MyEnum::Variant2(v8) => blk6,
  })

blk2:
Statements:
End:
  Match(match_enum(v2) {
    MyEnum::Variant1(v5) => blk3,
    MyEnum::Variant2(v6) => blk4,
  })

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

blk4:
Statements:
End:
  Goto(blk8, {v4 -> v11})

blk5:
Statements:
End:
  Goto(blk8, {v3 -> v11})

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

blk7:
Statements:
  (v9: core::felt252) <- 2
  (v10: core::box::Box::<core::felt252>) <- core::box::BoxImpl::<core::felt252>::new(v9)
End:
  Goto(blk8, {v10 -> v11})

blk8:
Statements:
End:
  Return(v11)
