From 43b861bfb01d6d52eeca85fe01058b4b77e785bd Mon Sep 17 00:00:00 2001 From: Lior Goldberg Date: Wed, 25 Jun 2025 21:08:46 +0300 Subject: [PATCH 1/2] WIP --- .../src/borrow_check/test_data/borrow_check | 102 ++++++++-- .../src/inline/test_data/inline | 116 +++++++---- .../src/lower/block_builder.rs | 23 ++- .../cairo-lang-lowering/src/lower/context.rs | 13 +- .../cairo-lang-lowering/src/lower/lower_if.rs | 168 ++++++++++++---- .../src/lower/lower_match.rs | 70 +++++-- crates/cairo-lang-lowering/src/lower/refs.rs | 4 +- .../src/lower/test_data/closure | 40 +++- .../src/lower/test_data/loop | 66 ++++--- .../src/optimizations/test_data/gas_redeposit | 152 +++++++++++---- .../src/optimizations/test_data/split_structs | 164 ++++++++-------- crates/cairo-lang-lowering/src/test_data/if | 180 ++++++++++++++++-- 12 files changed, 826 insertions(+), 272 deletions(-) diff --git a/crates/cairo-lang-lowering/src/borrow_check/test_data/borrow_check b/crates/cairo-lang-lowering/src/borrow_check/test_data/borrow_check index b2ff8a40332..e372787d58e 100644 --- a/crates/cairo-lang-lowering/src/borrow_check/test_data/borrow_check +++ b/crates/cairo-lang-lowering/src/borrow_check/test_data/borrow_check @@ -33,29 +33,49 @@ extern fn use_a_drop(x: ADrop) nopanic; //! > lowering Parameters: v0: test::ACopy, v1: test::ADrop blk0 (root): +Statements: +End: + Goto(blk1, {}) + +blk1: Statements: (v2: ()) <- struct_construct() (v3: core::bool) <- bool::True(v2{`true`}) End: Match(match_enum(v3{`true`}) { - bool::False(v5) => blk2, - bool::True(v4) => blk1, + bool::False(v5) => blk3, + bool::True(v4) => blk2, }) -blk1: +blk2: Statements: () <- test::use_a_copy(v0{`x`}) () <- test::use_a_drop(v1{`y`}) End: - Goto(blk3, {}) + Goto(blk4, {}) -blk2: +blk3: +Statements: +End: + Goto(blk6, {}) + +blk4: +Statements: +End: + Goto(blk7, {}) + +blk5: +Statements: +End: + Goto(blk5, {}) + +blk6: Statements: () <- test::use_a_drop(v1{`y`}) End: - Goto(blk3, {}) + Goto(blk7, {}) -blk3: +blk7: Statements: () <- test::use_a_copy(v0{`x`}) (v6: ()) <- struct_construct() @@ -117,28 +137,48 @@ note: Trait has no implementation in context: core::traits::Destruct:: lowering Parameters: v0: test::ACopy, v1: test::ADrop blk0 (root): +Statements: +End: + Goto(blk1, {}) + +blk1: Statements: (v2: ()) <- struct_construct() (v3: core::bool) <- bool::True(v2{`true`}) End: Match(match_enum(v3{`true`}) { - bool::False(v5) => blk2, - bool::True(v4) => blk1, + bool::False(v5) => blk3, + bool::True(v4) => blk2, }) -blk1: +blk2: Statements: () <- test::use_a_copy(v0{`x`}) () <- test::use_a_drop(v1{`y`}) End: - Goto(blk3, {}) + Goto(blk4, {}) -blk2: +blk3: Statements: End: - Goto(blk3, {}) + Goto(blk6, {}) -blk3: +blk4: +Statements: +End: + Goto(blk7, {}) + +blk5: +Statements: +End: + Goto(blk5, {}) + +blk6: +Statements: +End: + Goto(blk7, {}) + +blk7: Statements: End: Return(v1) @@ -344,27 +384,47 @@ note: Trait has no implementation in context: core::traits::Copy::. //! > lowering Parameters: v0: test::ADrop, v1: test::ADrop blk0 (root): +Statements: +End: + Goto(blk1, {}) + +blk1: Statements: (v2: ()) <- struct_construct() (v3: core::bool) <- bool::True(v2{`true`}) End: Match(match_enum(v3{`true`}) { - bool::False(v5) => blk2, - bool::True(v4) => blk1, + bool::False(v5) => blk3, + bool::True(v4) => blk2, }) -blk1: +blk2: Statements: () <- test::use_a_drop(v1{`y`}) End: - Goto(blk3, {v1 -> v6}) + Goto(blk4, {}) -blk2: +blk3: Statements: End: - Goto(blk3, {v0 -> v6}) + Goto(blk6, {}) -blk3: +blk4: +Statements: +End: + Goto(blk7, {v1 -> v6}) + +blk5: +Statements: +End: + Goto(blk5, {}) + +blk6: +Statements: +End: + Goto(blk7, {v0 -> v6}) + +blk7: Statements: End: Return(v6) diff --git a/crates/cairo-lang-lowering/src/inline/test_data/inline b/crates/cairo-lang-lowering/src/inline/test_data/inline index 9010cfc834d..2add953bd36 100644 --- a/crates/cairo-lang-lowering/src/inline/test_data/inline +++ b/crates/cairo-lang-lowering/src/inline/test_data/inline @@ -392,6 +392,11 @@ fn bar(a: felt252) -> felt252 { //! > before Parameters: v0: core::felt252 blk0 (root): +Statements: +End: + Goto(blk1, {}) + +blk1: Statements: (v1: core::felt252, v2: @core::felt252) <- snapshot(v0) (v3: core::felt252) <- 2 @@ -399,108 +404,143 @@ Statements: (v6: core::bool) <- core::Felt252PartialEq::eq(v2, v5) End: Match(match_enum(v6) { - bool::False(v9) => blk2, - bool::True(v7) => blk1, + bool::False(v9) => blk3, + bool::True(v7) => blk2, }) -blk1: +blk2: Statements: (v8: core::felt252) <- test::bar(v1) End: - Goto(blk3, {v8 -> v10}) + Goto(blk4, {v8 -> v10}) -blk2: +blk3: Statements: End: - Goto(blk3, {v1 -> v10}) + Goto(blk6, {}) -blk3: +blk4: Statements: End: - Return(v10) + Goto(blk7, {v1 -> v12, v10 -> v11}) + +blk5: +Statements: +End: + Goto(blk5, {}) + +blk6: +Statements: +End: + Goto(blk7, {v0 -> v12, v0 -> v11}) + +blk7: +Statements: +End: + Return(v11) //! > after Parameters: v0: core::felt252 blk0 (root): Statements: - (v1: core::felt252, v2: @core::felt252) <- snapshot(v0) - (v3: core::felt252) <- 2 - (v4: core::felt252, v5: @core::felt252) <- snapshot(v3) End: - Goto(blk4, {}) + Goto(blk1, {}) blk1: Statements: + (v1: core::felt252, v2: @core::felt252) <- snapshot(v0) + (v3: core::felt252) <- 2 + (v4: core::felt252, v5: @core::felt252) <- snapshot(v3) End: Goto(blk8, {}) blk2: Statements: End: - Goto(blk3, {v1 -> v10}) + Goto(blk12, {}) blk3: Statements: End: - Return(v10) + Goto(blk6, {}) blk4: Statements: - (v11: core::felt252) <- desnap(v2) - (v12: core::felt252) <- desnap(v5) - (v13: core::felt252) <- core::felt252_sub(v11, v12) End: - Match(match core::felt252_is_zero(v13) { - IsZeroResult::Zero => blk5, - IsZeroResult::NonZero(v14) => blk6, - }) + Goto(blk7, {v1 -> v12, v10 -> v11}) blk5: Statements: - (v15: ()) <- struct_construct() - (v16: core::bool) <- bool::True(v15) End: - Goto(blk7, {v16 -> v6}) + Goto(blk5, {}) blk6: Statements: - (v17: ()) <- struct_construct() - (v18: core::bool) <- bool::False(v17) End: - Goto(blk7, {v18 -> v6}) + Goto(blk7, {v0 -> v12, v0 -> v11}) blk7: Statements: End: - Match(match_enum(v6) { - bool::False(v9) => blk2, - bool::True(v7) => blk1, - }) + Return(v11) blk8: Statements: + (v13: core::felt252) <- desnap(v2) + (v14: core::felt252) <- desnap(v5) + (v15: core::felt252) <- core::felt252_sub(v13, v14) End: - Match(match core::felt252_is_zero(v1) { + Match(match core::felt252_is_zero(v15) { IsZeroResult::Zero => blk9, - IsZeroResult::NonZero(v19) => blk10, + IsZeroResult::NonZero(v16) => blk10, }) blk9: Statements: - (v20: core::felt252) <- 1 + (v17: ()) <- struct_construct() + (v18: core::bool) <- bool::True(v17) End: - Goto(blk11, {v20 -> v8}) + Goto(blk11, {v18 -> v6}) blk10: Statements: - (v21: core::felt252) <- 0 + (v19: ()) <- struct_construct() + (v20: core::bool) <- bool::False(v19) End: - Goto(blk11, {v21 -> v8}) + Goto(blk11, {v20 -> v6}) blk11: Statements: End: - Goto(blk3, {v8 -> v10}) + Match(match_enum(v6) { + bool::False(v9) => blk3, + bool::True(v7) => blk2, + }) + +blk12: +Statements: +End: + Match(match core::felt252_is_zero(v1) { + IsZeroResult::Zero => blk13, + IsZeroResult::NonZero(v21) => blk14, + }) + +blk13: +Statements: + (v22: core::felt252) <- 1 +End: + Goto(blk15, {v22 -> v8}) + +blk14: +Statements: + (v23: core::felt252) <- 0 +End: + Goto(blk15, {v23 -> v8}) + +blk15: +Statements: +End: + Goto(blk4, {v8 -> v10}) //! > lowering_diagnostics diff --git a/crates/cairo-lang-lowering/src/lower/block_builder.rs b/crates/cairo-lang-lowering/src/lower/block_builder.rs index dfca1ba4c17..5065c6d9a01 100644 --- a/crates/cairo-lang-lowering/src/lower/block_builder.rs +++ b/crates/cairo-lang-lowering/src/lower/block_builder.rs @@ -244,14 +244,33 @@ impl BlockBuilder { match_info: MatchInfo, sealed_blocks: Vec, location: LocationId, + ) -> LoweringResult { + self.merge_and_end( + ctx, + sealed_blocks, + location, + BlockEnd::Match { info: match_info.clone() }, + LoweringFlowError::Match(match_info), + ) + } + + /// Merges the sealed blocks and ends the current block with the given block end. + /// Replaces `self` with a sibling builder. + pub fn merge_and_end( + &mut self, + ctx: &mut LoweringContext<'_, '_>, + sealed_blocks: Vec, + location: LocationId, + block_end: BlockEnd, + err: LoweringFlowError, // TODO ) -> LoweringResult { let Some((merged_expr, following_block)) = self.merge_sealed(ctx, sealed_blocks, location) else { - return Err(LoweringFlowError::Match(match_info)); + return Err(err); }; let new_scope = self.sibling_block_builder(following_block); let prev_scope = std::mem::replace(self, new_scope); - prev_scope.finalize(ctx, BlockEnd::Match { info: match_info }); + prev_scope.finalize(ctx, block_end); Ok(merged_expr) } diff --git a/crates/cairo-lang-lowering/src/lower/context.rs b/crates/cairo-lang-lowering/src/lower/context.rs index 392524855e6..ce834580005 100644 --- a/crates/cairo-lang-lowering/src/lower/context.rs +++ b/crates/cairo-lang-lowering/src/lower/context.rs @@ -31,7 +31,10 @@ use crate::ids::{ }; use crate::lower::external::{extern_facade_expr, extern_facade_return_tys}; use crate::objects::Variable; -use crate::{Lowered, MatchArm, MatchExternInfo, MatchInfo, VarUsage, VariableId}; +use crate::{ + BlockEnd, BlockId, Lowered, MatchArm, MatchExternInfo, MatchInfo, VarRemapping, VarUsage, + VariableId, +}; pub struct VariableAllocator<'db> { pub db: &'db dyn LoweringGroup, @@ -418,6 +421,8 @@ pub enum LoweringFlowError { /// Every match arm is terminating - does not flow to parent builder /// e.g. returns or panics. Match(MatchInfo), + // TODO + Goto(BlockId), } impl LoweringFlowError { pub fn is_unreachable(&self) -> bool { @@ -425,7 +430,8 @@ impl LoweringFlowError { LoweringFlowError::Failed(_) => false, LoweringFlowError::Panic(_, _) | LoweringFlowError::Return(_, _) - | LoweringFlowError::Match(_) => true, + | LoweringFlowError::Match(_) + | LoweringFlowError::Goto(_) => true, } } } @@ -464,6 +470,9 @@ pub fn lowering_flow_error_to_sealed_block( LoweringFlowError::Match(info) => { builder.unreachable_match(ctx, info); } + LoweringFlowError::Goto(block_id) => { + builder.finalize(ctx, BlockEnd::Goto(block_id, VarRemapping::default())); + } } Ok(SealedBlockBuilder::Ends(block_id)) } diff --git a/crates/cairo-lang-lowering/src/lower/lower_if.rs b/crates/cairo-lang-lowering/src/lower/lower_if.rs index 4c51ae79b7b..564af149f04 100644 --- a/crates/cairo-lang-lowering/src/lower/lower_if.rs +++ b/crates/cairo-lang-lowering/src/lower/lower_if.rs @@ -1,8 +1,11 @@ +use std::cell::RefCell; + use cairo_lang_debug::DebugWithDb; use cairo_lang_diagnostics::Maybe; use cairo_lang_semantic as semantic; use cairo_lang_semantic::corelib; use cairo_lang_syntax::node::TypedStablePtr; +use cairo_lang_syntax::node::ids::SyntaxStablePtrId; use semantic::{Condition, MatchArmSelector}; use super::block_builder::{BlockBuilder, SealedBlockBuilder}; @@ -14,7 +17,7 @@ use crate::ids::LocationId; use crate::lower::context::VarRequest; use crate::lower::lower_match::{self, MatchArmWrapper}; use crate::lower::{create_subscope, lower_block, lower_expr, lower_expr_to_var_usage}; -use crate::{MatchArm, MatchEnumInfo, MatchInfo}; +use crate::{BlockEnd, MatchArm, MatchEnumInfo, MatchInfo, VarRemapping}; /// Represents an expression of the form: /// @@ -27,14 +30,40 @@ use crate::{MatchArm, MatchEnumInfo, MatchInfo}; pub struct ConditionedExpr<'a> { pub expr: semantic::ExprId, pub conditions: &'a [Condition], - pub else_block: Option, + pub else_block_tracker: Option>, } -impl ConditionedExpr<'_> { +impl<'a> ConditionedExpr<'a> { /// Returns a copy of self, without the first condition. - pub fn remove_first(&self) -> Self { + fn remove_first(&self) -> Self { Self { conditions: &self.conditions[1..], ..*self } } + + fn get_else_arm(&self) -> MatchArmWrapper<'a> { + if let Some(else_block_tracker) = &self.else_block_tracker { + MatchArmWrapper::SharedElseArm(*else_block_tracker) + } else { + MatchArmWrapper::DefaultClause + } + } +} + +/// Tracks information about the blocks leading to the else arm of a let-chain ([ConditionedExpr]). +#[derive(Clone, Copy)] +pub struct ElseBlockTracker<'a> { + /// A list of [SealedBlockBuilder] that should be merged into the `else` block. + pub block_builders: &'a RefCell>, + /// A stable pointer to the else block. + pub stable_ptr: SyntaxStablePtrId, +} + +impl<'a> ElseBlockTracker<'a> { + pub fn extend_block_builders( + &self, + block_builders: impl IntoIterator, + ) { + self.block_builders.borrow_mut().extend(block_builders); + } } /// Lowers an expression of type [semantic::ExprIf]. @@ -43,28 +72,96 @@ pub fn lower_expr_if( builder: &mut BlockBuilder, expr: &semantic::ExprIf, ) -> LoweringResult { - // Else block is not supported yet for multiple conditions. - if expr.conditions.len() > 1 { - if let Some(else_block) = expr.else_block { - let stable_ptr = ctx.function_body.arenas.exprs[else_block].stable_ptr().untyped(); - return Err(LoweringFlowError::Failed( - ctx.diagnostics.report(stable_ptr, LoweringDiagnosticKind::Unsupported), - )); - } + if let Some(else_block) = expr.else_block { + handle_if_with_else_block( + ctx, + builder, + expr.if_block, + &expr.conditions, + else_block, + ctx.get_location(expr.stable_ptr.untyped()), + ) + } else { + lower_conditioned_expr( + ctx, + builder, + &ConditionedExpr { + expr: expr.if_block, + conditions: &expr.conditions, + else_block_tracker: None, + }, + ) + } +} + +fn handle_if_with_else_block( + ctx: &mut LoweringContext<'_, '_>, + builder: &mut BlockBuilder, + if_block: semantic::ExprId, + conditions: &[Condition], + else_block: semantic::ExprId, + location: LocationId, +) -> LoweringResult { + // Extract the location of the else block. + let else_expr = &ctx.function_body.arenas.exprs[else_block]; + let else_stable_ptr = else_expr.stable_ptr().untyped(); + let else_location = ctx.get_location(else_stable_ptr); + + // Create two subscopes of builder: + // 1. `subscope_main` - contains the match logic and the success branch. + // 2. `subscope_else` - contains the else block. + let subscope_main = create_subscope(ctx, builder); + + // Construct the main block. + let block_main_id = subscope_main.block_id; + let else_sealed_blocks = RefCell::new(vec![]); + let else_block_tracker = + ElseBlockTracker { block_builders: &else_sealed_blocks, stable_ptr: else_stable_ptr }; + let conditioned_expr = ConditionedExpr { + expr: if_block, + conditions, + else_block_tracker: Some(else_block_tracker), + }; + + let block_main = lower_conditioned_expr_and_seal(ctx, subscope_main, &conditioned_expr) + .map_err(LoweringFlowError::Failed)?; + + let mut final_sealed_blocks = vec![block_main]; + + // Seal all the blocks collected from the else branches by pointing them to `subscope_else`. + // For each condition in the let-chain, we may have one or more blocks leading to the else + // branch. + let else_sealed_blocks = else_sealed_blocks.into_inner(); + if !else_sealed_blocks.is_empty() { + let mut subscope_else = create_subscope(ctx, builder); + subscope_else.merge_and_end( + ctx, + else_sealed_blocks, + else_location, + BlockEnd::Goto(subscope_else.block_id, VarRemapping::default()), // TODO: check. + LoweringFlowError::Goto(subscope_else.block_id), + )?; + + // Lower the content of the else block and seal it. + // TODO: remove lower_optional_else_block. + let block_else = lower_optional_else_block(ctx, subscope_else, Some(else_block), else_location) + .map_err(LoweringFlowError::Failed)?; + + final_sealed_blocks.push(block_else); } - lower_conditioned_expr( + + // Merge the main and else blocks. + builder.merge_and_end( ctx, - builder, - &ConditionedExpr { - expr: expr.if_block, - conditions: &expr.conditions, - else_block: expr.else_block, - }, + final_sealed_blocks, + location, + BlockEnd::Goto(block_main_id, VarRemapping::default()), + LoweringFlowError::Goto(block_main_id), ) } /// Lowers an expression of type [semantic::ExprIf]. -pub fn lower_if_bool_condition( +fn lower_if_bool_condition( ctx: &mut LoweringContext<'_, '_>, builder: &mut BlockBuilder, condition: semantic::ExprId, @@ -93,9 +190,20 @@ pub fn lower_if_bool_condition( let else_block_input_var_id = ctx.new_var(VarRequest { ty: unit_ty, location: condition_location }); - let block_else = - lower_optional_else_block(ctx, subscope_else, inner_expr.else_block, condition_location) - .map_err(LoweringFlowError::Failed)?; + + let mut blocks_to_seal = vec![block_main]; + + if let Some(tracker) = inner_expr.else_block_tracker { + tracker.extend_block_builders([subscope_else.goto_callsite(None)]); + } else { + let else_block = lowered_expr_to_block_scope_end( + ctx, + subscope_else, + Ok(LoweredExpr::Tuple { exprs: vec![], location: condition_location }), + ) + .map_err(LoweringFlowError::Failed)?; + blocks_to_seal.push(else_block); + } let match_info = MatchInfo::Enum(MatchEnumInfo { concrete_enum_id: corelib::core_bool_enum(db), @@ -114,16 +222,11 @@ pub fn lower_if_bool_condition( ], location: condition_location, }); - builder.merge_and_end_with_match( - ctx, - match_info, - vec![block_main, block_else], - condition_location, - ) + builder.merge_and_end_with_match(ctx, match_info, blocks_to_seal, condition_location) } /// Lowers an expression of type if where the condition is of type [semantic::Condition::Let]. -pub fn lower_if_let_condition( +fn lower_if_let_condition( ctx: &mut LoweringContext<'_, '_>, builder: &mut BlockBuilder, matched_expr_id: semantic::ExprId, @@ -147,10 +250,7 @@ pub fn lower_if_let_condition( ))); } - let else_arm = inner_expr - .else_block - .map(MatchArmWrapper::ElseClause) - .unwrap_or(MatchArmWrapper::DefaultClause); + let else_arm = inner_expr.get_else_arm(); let arms = vec![MatchArmWrapper::ConditionedArm(patterns, inner_expr), else_arm]; lower_match::lower_match_arms( diff --git a/crates/cairo-lang-lowering/src/lower/lower_match.rs b/crates/cairo-lang-lowering/src/lower/lower_match.rs index 922f66530bb..2a4968f8611 100644 --- a/crates/cairo-lang-lowering/src/lower/lower_match.rs +++ b/crates/cairo-lang-lowering/src/lower/lower_match.rs @@ -28,7 +28,7 @@ use super::context::{ LoweredExpr, LoweredExprExternEnum, LoweringContext, LoweringFlowError, LoweringResult, lowering_flow_error_to_sealed_block, }; -use super::lower_if::{ConditionedExpr, lower_conditioned_expr_and_seal}; +use super::lower_if::{ConditionedExpr, ElseBlockTracker, lower_conditioned_expr_and_seal}; use super::lower_let_else::lower_success_arm_body; use super::{ alloc_empty_block, generators, lower_expr_block, lower_expr_literal, lower_tail_expr, @@ -71,6 +71,9 @@ pub enum MatchArmWrapper<'a> { /// Similar to [Self::Arm], except that the expression is a conditioned expression /// (see [ConditionedExpr]). ConditionedArm(&'a [PatternId], ConditionedExpr<'a>), + /// Similar to [Self::ElseClause], except that `expr` is not provided, and the else block is + /// expected to be built and handled by the caller. + SharedElseArm(ElseBlockTracker<'a>), } impl<'a> From<&'a semantic::MatchArm> for MatchArmWrapper<'a> { @@ -86,7 +89,9 @@ impl MatchArmWrapper<'_> { MatchArmWrapper::Arm(patterns, _) | MatchArmWrapper::ConditionedArm(patterns, _) | MatchArmWrapper::LetElseSuccess(patterns, _, _) => Some(patterns), - MatchArmWrapper::ElseClause(_) | MatchArmWrapper::DefaultClause => None, + MatchArmWrapper::ElseClause(_) + | MatchArmWrapper::DefaultClause + | MatchArmWrapper::SharedElseArm(_) => None, } } @@ -223,6 +228,15 @@ fn get_underscore_pattern_path_and_mark_unreachable( }), ); } + MatchArmWrapper::SharedElseArm(tracker) => { + ctx.diagnostics.report( + tracker.stable_ptr, + MatchError(MatchError { + kind: match_type, + error: MatchDiagnostic::UnreachableMatchArm, + }), + ); + } } } @@ -1177,6 +1191,17 @@ trait EnumVariantScopeBuilder { ); continue; } + MatchArmWrapper::SharedElseArm(tracker) => { + try_push( + ctx, + match_type, + tracker.stable_ptr, + PatternPath { arm_index, pattern_index: None }, + &mut pattern_tree, + None, + ); + continue; + } MatchArmWrapper::Arm(patterns, _) | MatchArmWrapper::ConditionedArm(patterns, _) | MatchArmWrapper::LetElseSuccess(patterns, _, _) => patterns, @@ -1392,6 +1417,15 @@ trait EnumVariantScopeBuilder { ); } MatchArmWrapper::DefaultClause => (), + MatchArmWrapper::SharedElseArm(tracker) => { + ctx.diagnostics.report( + tracker.stable_ptr, + MatchError(MatchError { + kind: builder_context.kind, + error: MatchDiagnostic::UnreachableMatchArm, + }), + ); continue; + } } } return builder_context.builder.merge_and_end_with_match( @@ -1428,7 +1462,7 @@ trait EnumVariantScopeBuilder { let sealed = arm_blocks .into_iter() - .map(|(arm_index, group)| { + .filter_map(|(arm_index, group)| { lower_match_arm_expr_and_seal_patterns( ctx, &builder_context.empty_match_info, @@ -1438,6 +1472,7 @@ trait EnumVariantScopeBuilder { arm_index, group, ) + .transpose() }) .collect::>>()?; @@ -1709,7 +1744,7 @@ fn group_match_arms( .sorted_by_key(|MatchLeafBuilder { arm_index, .. }| *arm_index) .chunk_by(|MatchLeafBuilder { arm_index, .. }| *arm_index) .into_iter() - .map(|(arm_index, group)| { + .filter_map(|(arm_index, group)| { lower_match_arm_expr_and_seal_patterns( ctx, empty_match_info, @@ -1719,6 +1754,7 @@ fn group_match_arms( arm_index, group, ) + .transpose() }) .collect() } @@ -1734,7 +1770,7 @@ fn lower_match_arm_expr_and_seal_patterns( kind: MatchKind, arm_index: usize, group: impl IntoIterator, -) -> Result { +) -> Result, LoweringFlowError> { let arm = &arms[arm_index]; let mut lowering_inner_pattern_results_and_subscopes = group .into_iter() @@ -1742,7 +1778,9 @@ fn lower_match_arm_expr_and_seal_patterns( .collect::>(); // If the arm has only one pattern, there is no need to create a parent scope. - if lowering_inner_pattern_results_and_subscopes.len() == 1 { + if lowering_inner_pattern_results_and_subscopes.len() == 1 + && !matches!(arm, MatchArmWrapper::SharedElseArm(_)) + { let (lowering_inner_pattern_result, subscope) = lowering_inner_pattern_results_and_subscopes.pop().unwrap(); @@ -1753,15 +1791,14 @@ fn lower_match_arm_expr_and_seal_patterns( } Err(err) => lowering_flow_error_to_sealed_block(ctx, subscope, err), } - .map_err(LoweringFlowError::Failed); + .map_err(LoweringFlowError::Failed) + .map(Some); } // A parent block builder where the variables of each pattern are introduced. // The parent block should have the same semantics and changed_member_paths as any of // the child blocks. - let mut outer_subscope = lowering_inner_pattern_results_and_subscopes[0] - .1 - .sibling_block_builder(alloc_empty_block(ctx)); + let first_block_builder = lowering_inner_pattern_results_and_subscopes[0].1.clone(); let sealed_blocks: Vec<_> = lowering_inner_pattern_results_and_subscopes .into_iter() @@ -1774,13 +1811,21 @@ fn lower_match_arm_expr_and_seal_patterns( }) .collect::>>()?; + if let MatchArmWrapper::SharedElseArm(tracker) = arm { + tracker.extend_block_builders(sealed_blocks); + return Ok(None); + } + + let mut outer_subscope = first_block_builder.sibling_block_builder(alloc_empty_block(ctx)); outer_subscope.merge_and_end_with_match( ctx, empty_match_info.clone(), sealed_blocks, location, )?; - lower_arm_expr_and_seal(ctx, kind, arm, outer_subscope).map_err(LoweringFlowError::Failed) + lower_arm_expr_and_seal(ctx, kind, arm, outer_subscope) + .map_err(LoweringFlowError::Failed) + .map(Some) } /// Lowers the expression of a match arm and seals the block. @@ -1822,6 +1867,9 @@ fn lower_arm_expr_and_seal( (MatchArmWrapper::ConditionedArm(_, expr), _) => { lower_conditioned_expr_and_seal(ctx, subscope, expr) } + (MatchArmWrapper::SharedElseArm(_), _) => { + unreachable!("Invalid MatchKind for SharedElseArm."); + } } } diff --git a/crates/cairo-lang-lowering/src/lower/refs.rs b/crates/cairo-lang-lowering/src/lower/refs.rs index 42cd9a605f5..38dbcf0343b 100644 --- a/crates/cairo-lang-lowering/src/lower/refs.rs +++ b/crates/cairo-lang-lowering/src/lower/refs.rs @@ -36,7 +36,7 @@ impl SemanticLoweringMapping { /// Returns the topmost mapped member path containing the given member path, or None no such /// member path exists in the mapping. pub fn topmost_mapped_containing_member_path( - &mut self, + &self, mut member_path: MemberPath, ) -> Option { let mut res = None; @@ -53,7 +53,7 @@ impl SemanticLoweringMapping { /// Returns the scattered members of the given member path, or None if the member path is not /// scattered. - pub fn get_scattered_members(&mut self, member_path: &MemberPath) -> Option> { + pub fn get_scattered_members(&self, member_path: &MemberPath) -> Option> { let Some(Value::Scattered(scattered)) = self.scattered.get(member_path) else { return None; }; diff --git a/crates/cairo-lang-lowering/src/lower/test_data/closure b/crates/cairo-lang-lowering/src/lower/test_data/closure index 2d47df03ff7..86a29ddb3e1 100644 --- a/crates/cairo-lang-lowering/src/lower/test_data/closure +++ b/crates/cairo-lang-lowering/src/lower/test_data/closure @@ -397,6 +397,11 @@ Statements: (v3: core::felt252) <- struct_destructure(v2) (v4: core::felt252) <- 0 (v5: core::felt252, v6: @core::felt252) <- snapshot(v4) +End: + Goto(blk1, {}) + +blk1: +Statements: (v7: core::felt252) <- 1 (v8: core::felt252, v9: @core::felt252) <- snapshot(v7) (v10: core::felt252) <- 2 @@ -404,27 +409,42 @@ Statements: (v13: core::bool) <- core::Felt252PartialEq::eq(v9, v12) End: Match(match_enum(v13) { - bool::False(v17) => blk2, - bool::True(v14) => blk1, + bool::False(v17) => blk3, + bool::True(v14) => blk2, }) -blk1: +blk2: Statements: (v15: core::felt252, v16: @core::felt252) <- snapshot(v3) End: - Goto(blk3, {v15 -> v20, v16 -> v21}) + Goto(blk4, {v15 -> v18, v16 -> v19}) -blk2: +blk3: Statements: - (v18: core::felt252, v19: @core::felt252) <- snapshot(v3) End: - Goto(blk3, {v18 -> v20, v19 -> v21}) + Goto(blk6, {}) -blk3: +blk4: +Statements: +End: + Goto(blk7, {v18 -> v22, v19 -> v23}) + +blk5: +Statements: +End: + Goto(blk5, {}) + +blk6: +Statements: + (v20: core::felt252, v21: @core::felt252) <- snapshot(v3) +End: + Goto(blk7, {v20 -> v22, v21 -> v23}) + +blk7: Statements: - (v22: ()) <- struct_construct() + (v24: ()) <- struct_construct() End: - Return(v22) + Return(v24) Final lowering: diff --git a/crates/cairo-lang-lowering/src/lower/test_data/loop b/crates/cairo-lang-lowering/src/lower/test_data/loop index 60b823b341b..aebbe9ccac8 100644 --- a/crates/cairo-lang-lowering/src/lower/test_data/loop +++ b/crates/cairo-lang-lowering/src/lower/test_data/loop @@ -835,54 +835,74 @@ Generated loop lowering for source location: Parameters: v0: core::integer::u8 blk0 (root): Statements: - (v1: ()) <- struct_construct() - (v2: core::bool) <- bool::True(v1) End: - Match(match_enum(v2) { - bool::False(v5) => blk2, - bool::True(v3) => blk1, - }) + Goto(blk1, {}) blk1: Statements: - (v4: core::integer::u8) <- 0 + (v1: ()) <- struct_construct() + (v2: core::bool) <- bool::True(v1) End: - Goto(blk3, {v4 -> v7}) + Match(match_enum(v2) { + bool::False(v5) => blk3, + bool::True(v3) => blk2, + }) blk2: Statements: - (v6: core::integer::u8) <- 0 + (v4: core::integer::u8) <- 0 End: - Goto(blk3, {v6 -> v7}) + Goto(blk4, {v4 -> v6}) blk3: Statements: - (v8: core::integer::u8, v9: @core::integer::u8) <- snapshot(v7) - (v10: core::integer::u8) <- 0 - (v11: core::integer::u8, v12: @core::integer::u8) <- snapshot(v10) - (v13: core::bool) <- core::integer::U8PartialEq::eq(v9, v12) End: - Match(match_enum(v13) { - bool::False(v16) => blk5, - bool::True(v14) => blk4, - }) + Goto(blk6, {}) blk4: Statements: - (v15: ()) <- struct_construct() End: - Return(v8, v15) + Goto(blk7, {v6 -> v8}) blk5: Statements: End: - Goto(blk6, {}) + Goto(blk5, {}) blk6: Statements: - (v18: core::integer::u8, v17: ()) <- test::foo[45-203](v8) + (v7: core::integer::u8) <- 0 +End: + Goto(blk7, {v7 -> v8}) + +blk7: +Statements: + (v9: core::integer::u8, v10: @core::integer::u8) <- snapshot(v8) + (v11: core::integer::u8) <- 0 + (v12: core::integer::u8, v13: @core::integer::u8) <- snapshot(v11) + (v14: core::bool) <- core::integer::U8PartialEq::eq(v10, v13) +End: + Match(match_enum(v14) { + bool::False(v17) => blk9, + bool::True(v15) => blk8, + }) + +blk8: +Statements: + (v16: ()) <- struct_construct() +End: + Return(v9, v16) + +blk9: +Statements: +End: + Goto(blk10, {}) + +blk10: +Statements: + (v19: core::integer::u8, v18: ()) <- test::foo[45-203](v9) End: - Return(v18, v17) + Return(v19, v18) Final lowering: diff --git a/crates/cairo-lang-lowering/src/optimizations/test_data/gas_redeposit b/crates/cairo-lang-lowering/src/optimizations/test_data/gas_redeposit index b1d8231ce48..f33d7d1e061 100644 --- a/crates/cairo-lang-lowering/src/optimizations/test_data/gas_redeposit +++ b/crates/cairo-lang-lowering/src/optimizations/test_data/gas_redeposit @@ -33,6 +33,11 @@ fn heavy_op2() -> felt252 { //! > before Parameters: v0: core::felt252 blk0 (root): +Statements: +End: + Goto(blk1, {}) + +blk1: Statements: (v1: core::felt252, v2: @core::felt252) <- snapshot(v0) (v3: core::felt252) <- 0 @@ -40,30 +45,50 @@ Statements: (v6: core::bool) <- core::Felt252PartialEq::eq(v2, v5) End: Match(match_enum(v6) { - bool::False(v9) => blk2, - bool::True(v7) => blk1, + bool::False(v9) => blk3, + bool::True(v7) => blk2, }) -blk1: +blk2: Statements: (v8: core::felt252) <- test::heavy_op1() End: - Goto(blk3, {v8 -> v11}) + Goto(blk4, {v8 -> v10}) -blk2: +blk3: Statements: - (v10: core::felt252) <- test::heavy_op2() End: - Goto(blk3, {v10 -> v11}) + Goto(blk6, {}) -blk3: +blk4: +Statements: +End: + Goto(blk7, {v1 -> v13, v10 -> v12}) + +blk5: +Statements: +End: + Goto(blk5, {}) + +blk6: +Statements: + (v11: core::felt252) <- test::heavy_op2() +End: + Goto(blk7, {v0 -> v13, v11 -> v12}) + +blk7: Statements: End: - Return(v11) + Return(v12) //! > after Parameters: v0: core::felt252 blk0 (root): +Statements: +End: + Goto(blk1, {}) + +blk1: Statements: (v1: core::felt252, v2: @core::felt252) <- snapshot(v0) (v3: core::felt252) <- 0 @@ -71,26 +96,41 @@ Statements: (v6: core::bool) <- core::Felt252PartialEq::eq(v2, v5) End: Match(match_enum(v6) { - bool::False(v9) => blk2, - bool::True(v7) => blk1, + bool::False(v9) => blk3, + bool::True(v7) => blk2, }) -blk1: +blk2: Statements: (v8: core::felt252) <- test::heavy_op1() End: - Goto(blk3, {v8 -> v11}) + Goto(blk4, {v8 -> v10}) -blk2: +blk3: Statements: - (v10: core::felt252) <- test::heavy_op2() End: - Goto(blk3, {v10 -> v11}) + Goto(blk6, {}) -blk3: +blk4: +Statements: +End: + Goto(blk7, {v1 -> v13, v10 -> v12}) + +blk5: +Statements: +End: + Goto(blk5, {}) + +blk6: +Statements: + (v11: core::felt252) <- test::heavy_op2() +End: + Goto(blk7, {v0 -> v13, v11 -> v12}) + +blk7: Statements: End: - Return(v11) + Return(v12) //! > ========================================================================== @@ -127,6 +167,11 @@ fn heavy_op2() -> felt252 { //! > before Parameters: v0: core::felt252 blk0 (root): +Statements: +End: + Goto(blk1, {}) + +blk1: Statements: (v1: core::felt252, v2: @core::felt252) <- snapshot(v0) (v3: core::felt252) <- 0 @@ -134,30 +179,50 @@ Statements: (v6: core::bool) <- core::Felt252PartialEq::eq(v2, v5) End: Match(match_enum(v6) { - bool::False(v9) => blk2, - bool::True(v7) => blk1, + bool::False(v9) => blk3, + bool::True(v7) => blk2, }) -blk1: +blk2: Statements: (v8: core::felt252) <- test::heavy_op1() End: - Goto(blk3, {v8 -> v11}) + Goto(blk4, {v8 -> v10}) -blk2: +blk3: Statements: - (v10: core::felt252) <- test::heavy_op2() End: - Goto(blk3, {v10 -> v11}) + Goto(blk6, {}) -blk3: +blk4: +Statements: +End: + Goto(blk7, {v1 -> v13, v10 -> v12}) + +blk5: +Statements: +End: + Goto(blk5, {}) + +blk6: +Statements: + (v11: core::felt252) <- test::heavy_op2() +End: + Goto(blk7, {v0 -> v13, v11 -> v12}) + +blk7: Statements: End: - Return(v11) + Return(v12) //! > after Parameters: v0: core::felt252 blk0 (root): +Statements: +End: + Goto(blk1, {}) + +blk1: Statements: (v1: core::felt252, v2: @core::felt252) <- snapshot(v0) (v3: core::felt252) <- 0 @@ -165,27 +230,42 @@ Statements: (v6: core::bool) <- core::Felt252PartialEq::eq(v2, v5) End: Match(match_enum(v6) { - bool::False(v9) => blk2, - bool::True(v7) => blk1, + bool::False(v9) => blk3, + bool::True(v7) => blk2, }) -blk1: +blk2: Statements: () <- core::gas::redeposit_gas() (v8: core::felt252) <- test::heavy_op1() End: - Goto(blk3, {v8 -> v11}) + Goto(blk4, {v8 -> v10}) -blk2: +blk3: Statements: () <- core::gas::redeposit_gas() - (v10: core::felt252) <- test::heavy_op2() End: - Goto(blk3, {v10 -> v11}) + Goto(blk6, {}) -blk3: +blk4: +Statements: +End: + Goto(blk7, {v1 -> v13, v10 -> v12}) + +blk5: +Statements: +End: + Goto(blk5, {}) + +blk6: +Statements: + (v11: core::felt252) <- test::heavy_op2() +End: + Goto(blk7, {v0 -> v13, v11 -> v12}) + +blk7: Statements: End: - Return(v11) + Return(v12) //! > lowering_diagnostics diff --git a/crates/cairo-lang-lowering/src/optimizations/test_data/split_structs b/crates/cairo-lang-lowering/src/optimizations/test_data/split_structs index 3691dca6403..63e0aeed71a 100644 --- a/crates/cairo-lang-lowering/src/optimizations/test_data/split_structs +++ b/crates/cairo-lang-lowering/src/optimizations/test_data/split_structs @@ -623,48 +623,48 @@ Statements: (v18: core::felt252, v19: (core::felt252, core::felt252)) <- test::get_tuple::<(core::felt252, core::felt252)>() (v20: (core::felt252, (core::felt252, core::felt252))) <- struct_construct(v18, v19) End: - Goto(blk6, {v20 -> v21}) + Goto(blk6, {v0 -> v21, v20 -> v22}) blk5: Statements: - (v22: (core::felt252, (core::felt252, core::felt252))) <- struct_construct(v2, v1) + (v23: (core::felt252, (core::felt252, core::felt252))) <- struct_construct(v2, v1) End: - Goto(blk6, {v22 -> v21}) + Goto(blk6, {v2 -> v21, v23 -> v22}) blk6: Statements: - (v23: core::felt252, v24: @core::felt252) <- snapshot(v2) - (v25: core::felt252) <- 0 - (v26: core::felt252, v27: @core::felt252) <- snapshot(v25) - (v28: core::felt252) <- desnap(v24) - (v29: core::felt252) <- desnap(v27) - (v30: core::felt252) <- core::felt252_sub(v28, v29) + (v24: core::felt252, v25: @core::felt252) <- snapshot(v21) + (v26: core::felt252) <- 0 + (v27: core::felt252, v28: @core::felt252) <- snapshot(v26) + (v29: core::felt252) <- desnap(v25) + (v30: core::felt252) <- desnap(v28) + (v31: core::felt252) <- core::felt252_sub(v29, v30) End: - Match(match core::felt252_is_zero(v30) { + Match(match core::felt252_is_zero(v31) { IsZeroResult::Zero => blk7, - IsZeroResult::NonZero(v31) => blk8, + IsZeroResult::NonZero(v32) => blk8, }) blk7: Statements: - (v32: ()) <- struct_construct() - (v33: core::bool) <- bool::True(v32) + (v33: ()) <- struct_construct() + (v34: core::bool) <- bool::True(v33) End: - Goto(blk9, {v33 -> v34}) + Goto(blk9, {v34 -> v35}) blk8: Statements: - (v35: ()) <- struct_construct() - (v36: core::bool) <- bool::False(v35) + (v36: ()) <- struct_construct() + (v37: core::bool) <- bool::False(v36) End: - Goto(blk9, {v36 -> v34}) + Goto(blk9, {v37 -> v35}) blk9: Statements: End: - Match(match_enum(v34) { - bool::False(v37) => blk10, - bool::True(v38) => blk11, + Match(match_enum(v35) { + bool::False(v38) => blk10, + bool::True(v39) => blk11, }) blk10: @@ -674,39 +674,39 @@ End: blk11: Statements: - (v39: core::felt252, v40: (core::felt252, core::felt252)) <- struct_destructure(v21) - (v41: core::felt252, v42: @core::felt252) <- snapshot(v39) - (v43: core::felt252) <- 0 - (v44: core::felt252, v45: @core::felt252) <- snapshot(v43) - (v46: core::felt252) <- desnap(v42) - (v47: core::felt252) <- desnap(v45) - (v48: core::felt252) <- core::felt252_sub(v46, v47) + (v40: core::felt252, v41: (core::felt252, core::felt252)) <- struct_destructure(v22) + (v42: core::felt252, v43: @core::felt252) <- snapshot(v40) + (v44: core::felt252) <- 0 + (v45: core::felt252, v46: @core::felt252) <- snapshot(v44) + (v47: core::felt252) <- desnap(v43) + (v48: core::felt252) <- desnap(v46) + (v49: core::felt252) <- core::felt252_sub(v47, v48) End: - Match(match core::felt252_is_zero(v48) { + Match(match core::felt252_is_zero(v49) { IsZeroResult::Zero => blk12, - IsZeroResult::NonZero(v49) => blk13, + IsZeroResult::NonZero(v50) => blk13, }) blk12: Statements: - (v50: ()) <- struct_construct() - (v51: core::bool) <- bool::True(v50) + (v51: ()) <- struct_construct() + (v52: core::bool) <- bool::True(v51) End: - Goto(blk14, {v51 -> v52}) + Goto(blk14, {v52 -> v53}) blk13: Statements: - (v53: ()) <- struct_construct() - (v54: core::bool) <- bool::False(v53) + (v54: ()) <- struct_construct() + (v55: core::bool) <- bool::False(v54) End: - Goto(blk14, {v54 -> v52}) + Goto(blk14, {v55 -> v53}) blk14: Statements: End: - Match(match_enum(v52) { - bool::False(v55) => blk15, - bool::True(v56) => blk17, + Match(match_enum(v53) { + bool::False(v56) => blk15, + bool::True(v57) => blk17, }) blk15: @@ -717,14 +717,14 @@ End: blk16: Statements: End: - Return(v23) + Return(v24) blk17: Statements: - (v57: core::felt252, v58: core::felt252) <- struct_destructure(v40) - (v59: core::felt252) <- core::felt252_add(v57, v58) + (v58: core::felt252, v59: core::felt252) <- struct_destructure(v41) + (v60: core::felt252) <- core::felt252_add(v58, v59) End: - Return(v59) + Return(v60) //! > after Parameters: v0: core::felt252 @@ -767,49 +767,49 @@ End: blk4: Statements: (v18: core::felt252, v19: (core::felt252, core::felt252)) <- test::get_tuple::<(core::felt252, core::felt252)>() - (v64: core::felt252, v65: core::felt252) <- struct_destructure(v19) + (v65: core::felt252, v66: core::felt252) <- struct_destructure(v19) End: - Goto(blk6, {v18 -> v60, v64 -> v62, v65 -> v63}) + Goto(blk6, {v0 -> v21, v18 -> v61, v65 -> v63, v66 -> v64}) blk5: Statements: End: - Goto(blk6, {v2 -> v60, v0 -> v62, v0 -> v63}) + Goto(blk6, {v2 -> v21, v2 -> v61, v0 -> v63, v0 -> v64}) blk6: Statements: - (v23: core::felt252, v24: @core::felt252) <- snapshot(v2) - (v25: core::felt252) <- 0 - (v26: core::felt252, v27: @core::felt252) <- snapshot(v25) - (v28: core::felt252) <- desnap(v24) - (v29: core::felt252) <- desnap(v27) - (v30: core::felt252) <- core::felt252_sub(v28, v29) + (v24: core::felt252, v25: @core::felt252) <- snapshot(v21) + (v26: core::felt252) <- 0 + (v27: core::felt252, v28: @core::felt252) <- snapshot(v26) + (v29: core::felt252) <- desnap(v25) + (v30: core::felt252) <- desnap(v28) + (v31: core::felt252) <- core::felt252_sub(v29, v30) End: - Match(match core::felt252_is_zero(v30) { + Match(match core::felt252_is_zero(v31) { IsZeroResult::Zero => blk7, - IsZeroResult::NonZero(v31) => blk8, + IsZeroResult::NonZero(v32) => blk8, }) blk7: Statements: - (v32: ()) <- struct_construct() - (v33: core::bool) <- bool::True(v32) + (v33: ()) <- struct_construct() + (v34: core::bool) <- bool::True(v33) End: - Goto(blk9, {v33 -> v34}) + Goto(blk9, {v34 -> v35}) blk8: Statements: - (v35: ()) <- struct_construct() - (v36: core::bool) <- bool::False(v35) + (v36: ()) <- struct_construct() + (v37: core::bool) <- bool::False(v36) End: - Goto(blk9, {v36 -> v34}) + Goto(blk9, {v37 -> v35}) blk9: Statements: End: - Match(match_enum(v34) { - bool::False(v37) => blk10, - bool::True(v38) => blk11, + Match(match_enum(v35) { + bool::False(v38) => blk10, + bool::True(v39) => blk11, }) blk10: @@ -819,38 +819,38 @@ End: blk11: Statements: - (v41: core::felt252, v42: @core::felt252) <- snapshot(v60) - (v43: core::felt252) <- 0 - (v44: core::felt252, v45: @core::felt252) <- snapshot(v43) - (v46: core::felt252) <- desnap(v42) - (v47: core::felt252) <- desnap(v45) - (v48: core::felt252) <- core::felt252_sub(v46, v47) + (v42: core::felt252, v43: @core::felt252) <- snapshot(v61) + (v44: core::felt252) <- 0 + (v45: core::felt252, v46: @core::felt252) <- snapshot(v44) + (v47: core::felt252) <- desnap(v43) + (v48: core::felt252) <- desnap(v46) + (v49: core::felt252) <- core::felt252_sub(v47, v48) End: - Match(match core::felt252_is_zero(v48) { + Match(match core::felt252_is_zero(v49) { IsZeroResult::Zero => blk12, - IsZeroResult::NonZero(v49) => blk13, + IsZeroResult::NonZero(v50) => blk13, }) blk12: Statements: - (v50: ()) <- struct_construct() - (v51: core::bool) <- bool::True(v50) + (v51: ()) <- struct_construct() + (v52: core::bool) <- bool::True(v51) End: - Goto(blk14, {v51 -> v52}) + Goto(blk14, {v52 -> v53}) blk13: Statements: - (v53: ()) <- struct_construct() - (v54: core::bool) <- bool::False(v53) + (v54: ()) <- struct_construct() + (v55: core::bool) <- bool::False(v54) End: - Goto(blk14, {v54 -> v52}) + Goto(blk14, {v55 -> v53}) blk14: Statements: End: - Match(match_enum(v52) { - bool::False(v55) => blk15, - bool::True(v56) => blk17, + Match(match_enum(v53) { + bool::False(v56) => blk15, + bool::True(v57) => blk17, }) blk15: @@ -861,13 +861,13 @@ End: blk16: Statements: End: - Return(v23) + Return(v24) blk17: Statements: - (v59: core::felt252) <- core::felt252_add(v62, v63) + (v60: core::felt252) <- core::felt252_add(v63, v64) End: - Return(v59) + Return(v60) //! > ========================================================================== diff --git a/crates/cairo-lang-lowering/src/test_data/if b/crates/cairo-lang-lowering/src/test_data/if index 9077dbcca4c..a497671c12e 100644 --- a/crates/cairo-lang-lowering/src/test_data/if +++ b/crates/cairo-lang-lowering/src/test_data/if @@ -1091,11 +1091,11 @@ End: //! > Test if let with multiple conditions - with else block //! > test_runner_name -test_function_lowering(expect_diagnostics: true) +test_function_lowering(expect_diagnostics: false) //! > function -fn foo(a: Option>) -> felt252 { - if let Some(b) = a && let Some(c) = b { +fn foo(a: Option>, x: felt252) -> felt252 { + if let Some(b) = a && x == 5 && let Some(c) = b { c } else { 0 @@ -1110,13 +1110,171 @@ foo //! > semantic_diagnostics //! > lowering_diagnostics -error: Unsupported feature. - --> lib.cairo:4:12-6:5 - } else { - ____________^ -| 0 -| } -|_____^ //! > lowering_flat - +Parameters: v0: core::option::Option::>, v1: core::felt252 +blk0 (root): +Statements: +End: + Match(match_enum(v0) { + Option::Some(v2) => blk1, + Option::None(v3) => blk6, + }) + +blk1: +Statements: + (v4: core::felt252) <- 5 + (v5: core::felt252) <- core::felt252_sub(v1, v4) +End: + Match(match core::felt252_is_zero(v5) { + IsZeroResult::Zero => blk2, + IsZeroResult::NonZero(v6) => blk5, + }) + +blk2: +Statements: +End: + Match(match_enum(v2) { + Option::Some(v7) => blk3, + Option::None(v8) => blk4, + }) + +blk3: +Statements: +End: + Return(v7) + +blk4: +Statements: +End: + Goto(blk7, {}) + +blk5: +Statements: +End: + Goto(blk7, {}) + +blk6: +Statements: +End: + Goto(blk7, {}) + +blk7: +Statements: + (v9: core::felt252) <- 0 +End: + Return(v9) + +//! > ========================================================================== + +//! > Test let-chain with extern match + +//! > test_runner_name +test_function_lowering(expect_diagnostics: false) + +//! > function +extern fn bar() -> Option nopanic; + +fn foo(a: Option>, x: felt252) -> felt252 { + if let Some(b) = bar() && let Some(c) = bar() { + b + c + } else { + 0 + } +} + +//! > function_name +foo + +//! > module_code + +//! > semantic_diagnostics + +//! > lowering_diagnostics + +//! > lowering_flat +Parameters: v0: core::option::Option::>, v1: core::felt252 +blk0 (root): +Statements: +End: + Match(match test::bar() { + Option::Some(v2) => blk1, + Option::None => blk4, + }) + +blk1: +Statements: +End: + Match(match test::bar() { + Option::Some(v3) => blk2, + Option::None => blk3, + }) + +blk2: +Statements: + (v4: core::felt252) <- core::felt252_add(v2, v3) +End: + Return(v4) + +blk3: +Statements: +End: + Goto(blk5, {}) + +blk4: +Statements: +End: + Goto(blk5, {}) + +blk5: +Statements: + (v5: core::felt252) <- 0 +End: + Return(v5) + +//! > ========================================================================== + +//! > Return in all branches + +//! > test_runner_name +test_function_lowering(expect_diagnostics: false) + +//! > function +fn foo(x: felt252, y: felt252) -> felt252 { + if x == 0 { + return 1; + } else { + return 2; + } +} + +//! > function_name +foo + +//! > module_code + +//! > semantic_diagnostics + +//! > lowering_diagnostics + +//! > lowering_flat +Parameters: v0: core::felt252, v1: core::felt252 +blk0 (root): +Statements: +End: + Match(match core::felt252_is_zero(v0) { + IsZeroResult::Zero => blk1, + IsZeroResult::NonZero(v2) => blk2, + }) + +blk1: +Statements: + (v3: core::felt252) <- 1 +End: + Return(v3) + +blk2: +Statements: + (v4: core::felt252) <- 2 +End: + Return(v4) From f049070e38ab908af8e1263efe5949f51d62c4b5 Mon Sep 17 00:00:00 2001 From: Lior Goldberg Date: Wed, 2 Jul 2025 19:27:56 +0300 Subject: [PATCH 2/2] WIP --- .../src/inline/test_data/inline | 48 ++--- .../cairo-lang-lowering/src/lower/lower_if.rs | 23 ++- .../src/optimizations/test_data/gas_redeposit | 40 ++--- .../src/optimizations/test_data/split_structs | 164 +++++++++--------- crates/cairo-lang-lowering/src/test_data/if | 61 +++++++ 5 files changed, 202 insertions(+), 134 deletions(-) diff --git a/crates/cairo-lang-lowering/src/inline/test_data/inline b/crates/cairo-lang-lowering/src/inline/test_data/inline index 2add953bd36..8d6b7f465d8 100644 --- a/crates/cairo-lang-lowering/src/inline/test_data/inline +++ b/crates/cairo-lang-lowering/src/inline/test_data/inline @@ -417,12 +417,12 @@ End: blk3: Statements: End: - Goto(blk6, {}) + Goto(blk6, {v1 -> v11}) blk4: Statements: End: - Goto(blk7, {v1 -> v12, v10 -> v11}) + Goto(blk7, {v1 -> v13, v10 -> v12}) blk5: Statements: @@ -432,12 +432,12 @@ End: blk6: Statements: End: - Goto(blk7, {v0 -> v12, v0 -> v11}) + Goto(blk7, {v11 -> v13, v11 -> v12}) blk7: Statements: End: - Return(v11) + Return(v12) //! > after Parameters: v0: core::felt252 @@ -462,12 +462,12 @@ End: blk3: Statements: End: - Goto(blk6, {}) + Goto(blk6, {v1 -> v11}) blk4: Statements: End: - Goto(blk7, {v1 -> v12, v10 -> v11}) + Goto(blk7, {v1 -> v13, v10 -> v12}) blk5: Statements: @@ -477,37 +477,37 @@ End: blk6: Statements: End: - Goto(blk7, {v0 -> v12, v0 -> v11}) + Goto(blk7, {v11 -> v13, v11 -> v12}) blk7: Statements: End: - Return(v11) + Return(v12) blk8: Statements: - (v13: core::felt252) <- desnap(v2) - (v14: core::felt252) <- desnap(v5) - (v15: core::felt252) <- core::felt252_sub(v13, v14) + (v14: core::felt252) <- desnap(v2) + (v15: core::felt252) <- desnap(v5) + (v16: core::felt252) <- core::felt252_sub(v14, v15) End: - Match(match core::felt252_is_zero(v15) { + Match(match core::felt252_is_zero(v16) { IsZeroResult::Zero => blk9, - IsZeroResult::NonZero(v16) => blk10, + IsZeroResult::NonZero(v17) => blk10, }) blk9: Statements: - (v17: ()) <- struct_construct() - (v18: core::bool) <- bool::True(v17) + (v18: ()) <- struct_construct() + (v19: core::bool) <- bool::True(v18) End: - Goto(blk11, {v18 -> v6}) + Goto(blk11, {v19 -> v6}) blk10: Statements: - (v19: ()) <- struct_construct() - (v20: core::bool) <- bool::False(v19) + (v20: ()) <- struct_construct() + (v21: core::bool) <- bool::False(v20) End: - Goto(blk11, {v20 -> v6}) + Goto(blk11, {v21 -> v6}) blk11: Statements: @@ -522,20 +522,20 @@ Statements: End: Match(match core::felt252_is_zero(v1) { IsZeroResult::Zero => blk13, - IsZeroResult::NonZero(v21) => blk14, + IsZeroResult::NonZero(v22) => blk14, }) blk13: Statements: - (v22: core::felt252) <- 1 + (v23: core::felt252) <- 1 End: - Goto(blk15, {v22 -> v8}) + Goto(blk15, {v23 -> v8}) blk14: Statements: - (v23: core::felt252) <- 0 + (v24: core::felt252) <- 0 End: - Goto(blk15, {v23 -> v8}) + Goto(blk15, {v24 -> v8}) blk15: Statements: diff --git a/crates/cairo-lang-lowering/src/lower/lower_if.rs b/crates/cairo-lang-lowering/src/lower/lower_if.rs index 564af149f04..c5e48ead49e 100644 --- a/crates/cairo-lang-lowering/src/lower/lower_if.rs +++ b/crates/cairo-lang-lowering/src/lower/lower_if.rs @@ -16,7 +16,9 @@ use crate::diagnostic::{LoweringDiagnosticsBuilder, MatchDiagnostic, MatchError, use crate::ids::LocationId; use crate::lower::context::VarRequest; use crate::lower::lower_match::{self, MatchArmWrapper}; -use crate::lower::{create_subscope, lower_block, lower_expr, lower_expr_to_var_usage}; +use crate::lower::{ + alloc_empty_block, create_subscope, lower_block, lower_expr, lower_expr_to_var_usage, +}; use crate::{BlockEnd, MatchArm, MatchEnumInfo, MatchInfo, VarRemapping}; /// Represents an expression of the form: @@ -144,8 +146,9 @@ fn handle_if_with_else_block( // Lower the content of the else block and seal it. // TODO: remove lower_optional_else_block. - let block_else = lower_optional_else_block(ctx, subscope_else, Some(else_block), else_location) - .map_err(LoweringFlowError::Failed)?; + let block_else = + lower_optional_else_block(ctx, subscope_else, Some(else_block), else_location) + .map_err(LoweringFlowError::Failed)?; final_sealed_blocks.push(block_else); } @@ -185,17 +188,20 @@ fn lower_if_bool_condition( .map_err(LoweringFlowError::Failed)?; // Else block. - let subscope_else = create_subscope(ctx, builder); - let block_else_id = subscope_else.block_id; - let else_block_input_var_id = ctx.new_var(VarRequest { ty: unit_ty, location: condition_location }); let mut blocks_to_seal = vec![block_main]; - if let Some(tracker) = inner_expr.else_block_tracker { + let block_else_id = if let Some(tracker) = inner_expr.else_block_tracker { + let subscope_else = builder.sibling_block_builder(alloc_empty_block(ctx)); + let block_else_id = subscope_else.block_id; + tracker.extend_block_builders([subscope_else.goto_callsite(None)]); + block_else_id } else { + let subscope_else = builder.child_block_builder(alloc_empty_block(ctx)); + let block_else_id = subscope_else.block_id; let else_block = lowered_expr_to_block_scope_end( ctx, subscope_else, @@ -203,7 +209,8 @@ fn lower_if_bool_condition( ) .map_err(LoweringFlowError::Failed)?; blocks_to_seal.push(else_block); - } + block_else_id + }; let match_info = MatchInfo::Enum(MatchEnumInfo { concrete_enum_id: corelib::core_bool_enum(db), diff --git a/crates/cairo-lang-lowering/src/optimizations/test_data/gas_redeposit b/crates/cairo-lang-lowering/src/optimizations/test_data/gas_redeposit index f33d7d1e061..0b6709f6a95 100644 --- a/crates/cairo-lang-lowering/src/optimizations/test_data/gas_redeposit +++ b/crates/cairo-lang-lowering/src/optimizations/test_data/gas_redeposit @@ -58,12 +58,12 @@ End: blk3: Statements: End: - Goto(blk6, {}) + Goto(blk6, {v1 -> v11}) blk4: Statements: End: - Goto(blk7, {v1 -> v13, v10 -> v12}) + Goto(blk7, {v1 -> v14, v10 -> v13}) blk5: Statements: @@ -72,14 +72,14 @@ End: blk6: Statements: - (v11: core::felt252) <- test::heavy_op2() + (v12: core::felt252) <- test::heavy_op2() End: - Goto(blk7, {v0 -> v13, v11 -> v12}) + Goto(blk7, {v11 -> v14, v12 -> v13}) blk7: Statements: End: - Return(v12) + Return(v13) //! > after Parameters: v0: core::felt252 @@ -109,12 +109,12 @@ End: blk3: Statements: End: - Goto(blk6, {}) + Goto(blk6, {v1 -> v11}) blk4: Statements: End: - Goto(blk7, {v1 -> v13, v10 -> v12}) + Goto(blk7, {v1 -> v14, v10 -> v13}) blk5: Statements: @@ -123,14 +123,14 @@ End: blk6: Statements: - (v11: core::felt252) <- test::heavy_op2() + (v12: core::felt252) <- test::heavy_op2() End: - Goto(blk7, {v0 -> v13, v11 -> v12}) + Goto(blk7, {v11 -> v14, v12 -> v13}) blk7: Statements: End: - Return(v12) + Return(v13) //! > ========================================================================== @@ -192,12 +192,12 @@ End: blk3: Statements: End: - Goto(blk6, {}) + Goto(blk6, {v1 -> v11}) blk4: Statements: End: - Goto(blk7, {v1 -> v13, v10 -> v12}) + Goto(blk7, {v1 -> v14, v10 -> v13}) blk5: Statements: @@ -206,14 +206,14 @@ End: blk6: Statements: - (v11: core::felt252) <- test::heavy_op2() + (v12: core::felt252) <- test::heavy_op2() End: - Goto(blk7, {v0 -> v13, v11 -> v12}) + Goto(blk7, {v11 -> v14, v12 -> v13}) blk7: Statements: End: - Return(v12) + Return(v13) //! > after Parameters: v0: core::felt252 @@ -245,12 +245,12 @@ blk3: Statements: () <- core::gas::redeposit_gas() End: - Goto(blk6, {}) + Goto(blk6, {v1 -> v11}) blk4: Statements: End: - Goto(blk7, {v1 -> v13, v10 -> v12}) + Goto(blk7, {v1 -> v14, v10 -> v13}) blk5: Statements: @@ -259,13 +259,13 @@ End: blk6: Statements: - (v11: core::felt252) <- test::heavy_op2() + (v12: core::felt252) <- test::heavy_op2() End: - Goto(blk7, {v0 -> v13, v11 -> v12}) + Goto(blk7, {v11 -> v14, v12 -> v13}) blk7: Statements: End: - Return(v12) + Return(v13) //! > lowering_diagnostics diff --git a/crates/cairo-lang-lowering/src/optimizations/test_data/split_structs b/crates/cairo-lang-lowering/src/optimizations/test_data/split_structs index 63e0aeed71a..3691dca6403 100644 --- a/crates/cairo-lang-lowering/src/optimizations/test_data/split_structs +++ b/crates/cairo-lang-lowering/src/optimizations/test_data/split_structs @@ -623,48 +623,48 @@ Statements: (v18: core::felt252, v19: (core::felt252, core::felt252)) <- test::get_tuple::<(core::felt252, core::felt252)>() (v20: (core::felt252, (core::felt252, core::felt252))) <- struct_construct(v18, v19) End: - Goto(blk6, {v0 -> v21, v20 -> v22}) + Goto(blk6, {v20 -> v21}) blk5: Statements: - (v23: (core::felt252, (core::felt252, core::felt252))) <- struct_construct(v2, v1) + (v22: (core::felt252, (core::felt252, core::felt252))) <- struct_construct(v2, v1) End: - Goto(blk6, {v2 -> v21, v23 -> v22}) + Goto(blk6, {v22 -> v21}) blk6: Statements: - (v24: core::felt252, v25: @core::felt252) <- snapshot(v21) - (v26: core::felt252) <- 0 - (v27: core::felt252, v28: @core::felt252) <- snapshot(v26) - (v29: core::felt252) <- desnap(v25) - (v30: core::felt252) <- desnap(v28) - (v31: core::felt252) <- core::felt252_sub(v29, v30) + (v23: core::felt252, v24: @core::felt252) <- snapshot(v2) + (v25: core::felt252) <- 0 + (v26: core::felt252, v27: @core::felt252) <- snapshot(v25) + (v28: core::felt252) <- desnap(v24) + (v29: core::felt252) <- desnap(v27) + (v30: core::felt252) <- core::felt252_sub(v28, v29) End: - Match(match core::felt252_is_zero(v31) { + Match(match core::felt252_is_zero(v30) { IsZeroResult::Zero => blk7, - IsZeroResult::NonZero(v32) => blk8, + IsZeroResult::NonZero(v31) => blk8, }) blk7: Statements: - (v33: ()) <- struct_construct() - (v34: core::bool) <- bool::True(v33) + (v32: ()) <- struct_construct() + (v33: core::bool) <- bool::True(v32) End: - Goto(blk9, {v34 -> v35}) + Goto(blk9, {v33 -> v34}) blk8: Statements: - (v36: ()) <- struct_construct() - (v37: core::bool) <- bool::False(v36) + (v35: ()) <- struct_construct() + (v36: core::bool) <- bool::False(v35) End: - Goto(blk9, {v37 -> v35}) + Goto(blk9, {v36 -> v34}) blk9: Statements: End: - Match(match_enum(v35) { - bool::False(v38) => blk10, - bool::True(v39) => blk11, + Match(match_enum(v34) { + bool::False(v37) => blk10, + bool::True(v38) => blk11, }) blk10: @@ -674,39 +674,39 @@ End: blk11: Statements: - (v40: core::felt252, v41: (core::felt252, core::felt252)) <- struct_destructure(v22) - (v42: core::felt252, v43: @core::felt252) <- snapshot(v40) - (v44: core::felt252) <- 0 - (v45: core::felt252, v46: @core::felt252) <- snapshot(v44) - (v47: core::felt252) <- desnap(v43) - (v48: core::felt252) <- desnap(v46) - (v49: core::felt252) <- core::felt252_sub(v47, v48) + (v39: core::felt252, v40: (core::felt252, core::felt252)) <- struct_destructure(v21) + (v41: core::felt252, v42: @core::felt252) <- snapshot(v39) + (v43: core::felt252) <- 0 + (v44: core::felt252, v45: @core::felt252) <- snapshot(v43) + (v46: core::felt252) <- desnap(v42) + (v47: core::felt252) <- desnap(v45) + (v48: core::felt252) <- core::felt252_sub(v46, v47) End: - Match(match core::felt252_is_zero(v49) { + Match(match core::felt252_is_zero(v48) { IsZeroResult::Zero => blk12, - IsZeroResult::NonZero(v50) => blk13, + IsZeroResult::NonZero(v49) => blk13, }) blk12: Statements: - (v51: ()) <- struct_construct() - (v52: core::bool) <- bool::True(v51) + (v50: ()) <- struct_construct() + (v51: core::bool) <- bool::True(v50) End: - Goto(blk14, {v52 -> v53}) + Goto(blk14, {v51 -> v52}) blk13: Statements: - (v54: ()) <- struct_construct() - (v55: core::bool) <- bool::False(v54) + (v53: ()) <- struct_construct() + (v54: core::bool) <- bool::False(v53) End: - Goto(blk14, {v55 -> v53}) + Goto(blk14, {v54 -> v52}) blk14: Statements: End: - Match(match_enum(v53) { - bool::False(v56) => blk15, - bool::True(v57) => blk17, + Match(match_enum(v52) { + bool::False(v55) => blk15, + bool::True(v56) => blk17, }) blk15: @@ -717,14 +717,14 @@ End: blk16: Statements: End: - Return(v24) + Return(v23) blk17: Statements: - (v58: core::felt252, v59: core::felt252) <- struct_destructure(v41) - (v60: core::felt252) <- core::felt252_add(v58, v59) + (v57: core::felt252, v58: core::felt252) <- struct_destructure(v40) + (v59: core::felt252) <- core::felt252_add(v57, v58) End: - Return(v60) + Return(v59) //! > after Parameters: v0: core::felt252 @@ -767,49 +767,49 @@ End: blk4: Statements: (v18: core::felt252, v19: (core::felt252, core::felt252)) <- test::get_tuple::<(core::felt252, core::felt252)>() - (v65: core::felt252, v66: core::felt252) <- struct_destructure(v19) + (v64: core::felt252, v65: core::felt252) <- struct_destructure(v19) End: - Goto(blk6, {v0 -> v21, v18 -> v61, v65 -> v63, v66 -> v64}) + Goto(blk6, {v18 -> v60, v64 -> v62, v65 -> v63}) blk5: Statements: End: - Goto(blk6, {v2 -> v21, v2 -> v61, v0 -> v63, v0 -> v64}) + Goto(blk6, {v2 -> v60, v0 -> v62, v0 -> v63}) blk6: Statements: - (v24: core::felt252, v25: @core::felt252) <- snapshot(v21) - (v26: core::felt252) <- 0 - (v27: core::felt252, v28: @core::felt252) <- snapshot(v26) - (v29: core::felt252) <- desnap(v25) - (v30: core::felt252) <- desnap(v28) - (v31: core::felt252) <- core::felt252_sub(v29, v30) + (v23: core::felt252, v24: @core::felt252) <- snapshot(v2) + (v25: core::felt252) <- 0 + (v26: core::felt252, v27: @core::felt252) <- snapshot(v25) + (v28: core::felt252) <- desnap(v24) + (v29: core::felt252) <- desnap(v27) + (v30: core::felt252) <- core::felt252_sub(v28, v29) End: - Match(match core::felt252_is_zero(v31) { + Match(match core::felt252_is_zero(v30) { IsZeroResult::Zero => blk7, - IsZeroResult::NonZero(v32) => blk8, + IsZeroResult::NonZero(v31) => blk8, }) blk7: Statements: - (v33: ()) <- struct_construct() - (v34: core::bool) <- bool::True(v33) + (v32: ()) <- struct_construct() + (v33: core::bool) <- bool::True(v32) End: - Goto(blk9, {v34 -> v35}) + Goto(blk9, {v33 -> v34}) blk8: Statements: - (v36: ()) <- struct_construct() - (v37: core::bool) <- bool::False(v36) + (v35: ()) <- struct_construct() + (v36: core::bool) <- bool::False(v35) End: - Goto(blk9, {v37 -> v35}) + Goto(blk9, {v36 -> v34}) blk9: Statements: End: - Match(match_enum(v35) { - bool::False(v38) => blk10, - bool::True(v39) => blk11, + Match(match_enum(v34) { + bool::False(v37) => blk10, + bool::True(v38) => blk11, }) blk10: @@ -819,38 +819,38 @@ End: blk11: Statements: - (v42: core::felt252, v43: @core::felt252) <- snapshot(v61) - (v44: core::felt252) <- 0 - (v45: core::felt252, v46: @core::felt252) <- snapshot(v44) - (v47: core::felt252) <- desnap(v43) - (v48: core::felt252) <- desnap(v46) - (v49: core::felt252) <- core::felt252_sub(v47, v48) + (v41: core::felt252, v42: @core::felt252) <- snapshot(v60) + (v43: core::felt252) <- 0 + (v44: core::felt252, v45: @core::felt252) <- snapshot(v43) + (v46: core::felt252) <- desnap(v42) + (v47: core::felt252) <- desnap(v45) + (v48: core::felt252) <- core::felt252_sub(v46, v47) End: - Match(match core::felt252_is_zero(v49) { + Match(match core::felt252_is_zero(v48) { IsZeroResult::Zero => blk12, - IsZeroResult::NonZero(v50) => blk13, + IsZeroResult::NonZero(v49) => blk13, }) blk12: Statements: - (v51: ()) <- struct_construct() - (v52: core::bool) <- bool::True(v51) + (v50: ()) <- struct_construct() + (v51: core::bool) <- bool::True(v50) End: - Goto(blk14, {v52 -> v53}) + Goto(blk14, {v51 -> v52}) blk13: Statements: - (v54: ()) <- struct_construct() - (v55: core::bool) <- bool::False(v54) + (v53: ()) <- struct_construct() + (v54: core::bool) <- bool::False(v53) End: - Goto(blk14, {v55 -> v53}) + Goto(blk14, {v54 -> v52}) blk14: Statements: End: - Match(match_enum(v53) { - bool::False(v56) => blk15, - bool::True(v57) => blk17, + Match(match_enum(v52) { + bool::False(v55) => blk15, + bool::True(v56) => blk17, }) blk15: @@ -861,13 +861,13 @@ End: blk16: Statements: End: - Return(v24) + Return(v23) blk17: Statements: - (v60: core::felt252) <- core::felt252_add(v63, v64) + (v59: core::felt252) <- core::felt252_add(v62, v63) End: - Return(v60) + Return(v59) //! > ========================================================================== diff --git a/crates/cairo-lang-lowering/src/test_data/if b/crates/cairo-lang-lowering/src/test_data/if index a497671c12e..baca39308cd 100644 --- a/crates/cairo-lang-lowering/src/test_data/if +++ b/crates/cairo-lang-lowering/src/test_data/if @@ -1278,3 +1278,64 @@ Statements: (v4: core::felt252) <- 2 End: Return(v4) + +//! > ========================================================================== + +//! > Destruct self in condition + +//! > test_runner_name +test_function_lowering(expect_diagnostics: false) + +//! > function +fn foo(ref self: MyStruct) -> Option { + if self.x != self.y { + let value = self.x; + self.x = value + 1; + Some(value) + } else { + None + } +} + +//! > function_name +foo + +//! > module_code +#[derive(Drop)] +struct MyStruct { + x: felt252, + y: felt252, +} + +//! > semantic_diagnostics + +//! > lowering_diagnostics + +//! > lowering_flat +Parameters: v0: test::MyStruct +blk0 (root): +Statements: + (v1: core::felt252, v2: core::felt252) <- struct_destructure(v0) + (v3: core::felt252) <- core::felt252_sub(v1, v2) +End: + Match(match core::felt252_is_zero(v3) { + IsZeroResult::Zero => blk1, + IsZeroResult::NonZero(v4) => blk2, + }) + +blk1: +Statements: + (v5: ()) <- struct_construct() + (v6: core::option::Option::) <- Option::None(v5) + (v7: test::MyStruct) <- struct_construct(v1, v2) +End: + Return(v7, v6) + +blk2: +Statements: + (v8: core::felt252) <- 1 + (v9: core::felt252) <- core::felt252_add(v1, v8) + (v10: test::MyStruct) <- struct_construct(v9, v2) + (v11: core::option::Option::) <- Option::Some(v1) +End: + Return(v10, v11)