Skip to content

Commit 6b0e569

Browse files
Represent match arm wrapper as an enum with explicit cases
commit-id:415bf8b4
1 parent 5dc04c5 commit 6b0e569

File tree

3 files changed

+121
-76
lines changed

3 files changed

+121
-76
lines changed

crates/cairo-lang-lowering/src/lower/lower_if.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,8 @@ pub fn lower_expr_if_let(
111111
}
112112

113113
let arms = vec![
114-
MatchArmWrapper { patterns: patterns.into(), expr: Some(expr.if_block) },
115-
MatchArmWrapper { patterns: vec![], expr: expr.else_block },
114+
MatchArmWrapper::Arm(patterns, expr.if_block),
115+
expr.else_block.map(MatchArmWrapper::ElseClause).unwrap_or(MatchArmWrapper::DefaultClause),
116116
];
117117

118118
lower_match::lower_match_arms(

crates/cairo-lang-lowering/src/lower/lower_match.rs

Lines changed: 118 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -48,16 +48,51 @@ struct ExtractedEnumDetails {
4848
n_snapshots: usize,
4949
}
5050

51-
/// MatchArm wrapper that allows for optional expression clause.
52-
/// Used in the case of if-let with missing else clause.
53-
pub struct MatchArmWrapper {
54-
pub patterns: Vec<PatternId>,
55-
pub expr: Option<semantic::ExprId>,
51+
/// A wrapper enum to provide a unified interface for handling different types of match arms
52+
/// during the lowering phase of the compiler, allowing for consistent pattern matching
53+
/// and expression evaluation across different match-like constructs.
54+
pub enum MatchArmWrapper<'a> {
55+
/// A match arm. Patterns (non-empty) guard the expression to evaluate.
56+
Arm(&'a [PatternId], semantic::ExprId),
57+
/// Else clause (no patterns) and it's expression to evaluate (if-let).
58+
ElseClause(semantic::ExprId),
59+
/// Default clause when else clause is not provided (if-let/while-let).
60+
DefaultClause,
5661
}
5762

58-
impl From<&semantic::MatchArm> for MatchArmWrapper {
59-
fn from(arm: &semantic::MatchArm) -> Self {
60-
Self { patterns: arm.patterns.clone(), expr: Some(arm.expression) }
63+
impl<'a> From<&'a semantic::MatchArm> for MatchArmWrapper<'a> {
64+
fn from(arm: &'a semantic::MatchArm) -> Self {
65+
MatchArmWrapper::Arm(&arm.patterns, arm.expression)
66+
}
67+
}
68+
69+
impl MatchArmWrapper<'_> {
70+
/// Returns the expression of the guarded by the match arm.
71+
pub fn expr(&self) -> Option<semantic::ExprId> {
72+
match self {
73+
MatchArmWrapper::Arm(_, expr) => Some(*expr),
74+
MatchArmWrapper::ElseClause(expr) => Some(*expr),
75+
MatchArmWrapper::DefaultClause => None,
76+
}
77+
}
78+
79+
/// Returns the patterns of the match arm.
80+
pub fn patterns(&self) -> Option<&[PatternId]> {
81+
match self {
82+
MatchArmWrapper::Arm(patterns, _) => Some(patterns),
83+
MatchArmWrapper::ElseClause(_) => None,
84+
MatchArmWrapper::DefaultClause => None,
85+
}
86+
}
87+
88+
/// Try and extract the pattern from the match arm by index.
89+
/// Returns None if the arm is a missing clause, else clause.
90+
pub fn pattern<'a>(
91+
&self,
92+
ctx: &'a LoweringContext<'_, '_>,
93+
index: usize,
94+
) -> Option<&'a Pattern> {
95+
self.patterns().map(|patterns| &ctx.function_body.arenas.patterns[patterns[index]])
6196
}
6297
}
6398

@@ -126,65 +161,69 @@ struct PatternPath {
126161
/// Returns an option containing the PatternPath of the underscore pattern, if it exists.
127162
fn get_underscore_pattern_path_and_mark_unreachable(
128163
ctx: &mut LoweringContext<'_, '_>,
129-
arms: &[MatchArmWrapper],
164+
arms: &[MatchArmWrapper<'_>],
130165
match_type: MatchKind,
131166
) -> Option<PatternPath> {
132167
let otherwise_variant = arms
133168
.iter()
134169
.enumerate()
135170
.filter_map(|(arm_index, arm)| {
136-
let pattern_index = if arm.patterns.is_empty() {
137-
// Special path for if-let else clause where no patterns exist.
138-
None
139-
} else {
140-
let position = arm.patterns.iter().position(|pattern| {
141-
matches!(
142-
ctx.function_body.arenas.patterns[*pattern],
143-
semantic::Pattern::Otherwise(_)
144-
)
145-
})?;
146-
Some(position)
171+
let pattern_index = match arm {
172+
MatchArmWrapper::Arm(patterns, _) => {
173+
let position = patterns.iter().position(|pattern| {
174+
matches!(
175+
ctx.function_body.arenas.patterns[*pattern],
176+
semantic::Pattern::Otherwise(_)
177+
)
178+
})?;
179+
Some(position)
180+
}
181+
MatchArmWrapper::DefaultClause | MatchArmWrapper::ElseClause(_) => None,
147182
};
148183
Some(PatternPath { arm_index, pattern_index })
149184
})
150185
.next()?;
151186

152187
for arm in arms.iter().skip(otherwise_variant.arm_index + 1) {
153-
if arm.patterns.is_empty() && arm.expr.is_some() {
154-
let expr = ctx.function_body.arenas.exprs[arm.expr.unwrap()].clone();
155-
ctx.diagnostics.report(
156-
&expr,
157-
MatchError(MatchError {
158-
kind: match_type,
159-
error: MatchDiagnostic::UnreachableMatchArm,
160-
}),
161-
);
188+
match arm {
189+
MatchArmWrapper::Arm(patterns, _expr) => {
190+
for pattern in patterns.iter() {
191+
let pattern_ptr = ctx.function_body.arenas.patterns[*pattern].stable_ptr();
192+
ctx.diagnostics.report(
193+
pattern_ptr,
194+
MatchError(MatchError {
195+
kind: match_type,
196+
error: MatchDiagnostic::UnreachableMatchArm,
197+
}),
198+
);
199+
}
200+
}
201+
MatchArmWrapper::DefaultClause => continue,
202+
MatchArmWrapper::ElseClause(e) => {
203+
let expr_ptr = ctx.function_body.arenas.exprs[*e].stable_ptr();
204+
ctx.diagnostics.report(
205+
expr_ptr,
206+
MatchError(MatchError {
207+
kind: match_type,
208+
error: MatchDiagnostic::UnreachableMatchArm,
209+
}),
210+
);
211+
}
162212
}
163-
for pattern in arm.patterns.iter() {
164-
let pattern = ctx.function_body.arenas.patterns[*pattern].clone();
213+
}
214+
215+
if let Some(patterns) = arms[otherwise_variant.arm_index].patterns() {
216+
for pattern in patterns.iter().skip(otherwise_variant.pattern_index.unwrap_or(0) + 1) {
217+
let pattern = &ctx.function_body.arenas.patterns[*pattern];
165218
ctx.diagnostics.report(
166-
&pattern,
219+
pattern.stable_ptr(),
167220
MatchError(MatchError {
168221
kind: match_type,
169222
error: MatchDiagnostic::UnreachableMatchArm,
170223
}),
171224
);
172225
}
173226
}
174-
for pattern in arms[otherwise_variant.arm_index]
175-
.patterns
176-
.iter()
177-
.skip(otherwise_variant.pattern_index.unwrap_or(0) + 1)
178-
{
179-
let pattern = ctx.function_body.arenas.patterns[*pattern].clone();
180-
ctx.diagnostics.report(
181-
&pattern,
182-
MatchError(MatchError {
183-
kind: match_type,
184-
error: MatchDiagnostic::UnreachableMatchArm,
185-
}),
186-
);
187-
}
188227

189228
Some(otherwise_variant)
190229
}
@@ -289,7 +328,7 @@ impl VariantMatchTree {
289328
/// Returns a map from variants to their corresponding pattern path in a match statement.
290329
fn get_variant_to_arm_map(
291330
ctx: &mut LoweringContext<'_, '_>,
292-
arms: &[MatchArmWrapper],
331+
arms: &[MatchArmWrapper<'_>],
293332
concrete_enum_id: semantic::ConcreteEnumId,
294333
match_type: MatchKind,
295334
) -> LoweringResult<UnorderedHashMap<semantic::ConcreteVariant, PatternPath>> {
@@ -298,7 +337,10 @@ fn get_variant_to_arm_map(
298337
// A::B(_). Check pattern is legal and collect paths.
299338
let mut variant_map = VariantMatchTree::Empty;
300339
for (arm_index, arm) in arms.iter().enumerate() {
301-
for (pattern_index, mut pattern) in arm.patterns.iter().copied().enumerate() {
340+
let Some(patterns) = arm.patterns() else {
341+
continue;
342+
};
343+
for (pattern_index, mut pattern) in patterns.iter().copied().enumerate() {
302344
let pattern_path = PatternPath { arm_index, pattern_index: Some(pattern_index) };
303345
let pattern_ptr = ctx.function_body.arenas.patterns[pattern].stable_ptr();
304346

@@ -531,13 +573,16 @@ fn insert_tuple_path_patterns(
531573
/// Returns a map from a matching paths to their corresponding pattern path in a match statement.
532574
fn get_variants_to_arm_map_tuple<'a>(
533575
ctx: &mut LoweringContext<'_, '_>,
534-
arms: impl Iterator<Item = &'a MatchArmWrapper>,
576+
arms: impl Iterator<Item = &'a MatchArmWrapper<'a>>,
535577
extracted_enums_details: &[ExtractedEnumDetails],
536578
match_type: MatchKind,
537579
) -> LoweringResult<UnorderedHashMap<MatchingPath, PatternPath>> {
538580
let mut map = UnorderedHashMap::default();
539581
for (arm_index, arm) in arms.enumerate() {
540-
for (pattern_index, pattern) in arm.patterns.iter().enumerate() {
582+
let Some(patterns) = arm.patterns() else {
583+
continue;
584+
};
585+
for (pattern_index, pattern) in patterns.iter().enumerate() {
541586
let pattern = ctx.function_body.arenas.patterns[*pattern].clone();
542587
if let semantic::Pattern::Otherwise(_) = pattern {
543588
break;
@@ -599,7 +644,7 @@ struct LoweringMatchTupleContext {
599644
fn lower_tuple_match_arm(
600645
ctx: &mut LoweringContext<'_, '_>,
601646
mut builder: BlockBuilder,
602-
arms: &[MatchArmWrapper],
647+
arms: &[MatchArmWrapper<'_>],
603648
match_tuple_ctx: &mut LoweringMatchTupleContext,
604649
leaves_builders: &mut Vec<MatchLeafBuilder>,
605650
match_type: MatchKind,
@@ -623,11 +668,12 @@ fn lower_tuple_match_arm(
623668
}),
624669
))
625670
})?;
626-
let pattern = pattern_path.pattern_index.map(|pattern_index| {
627-
ctx.function_body.arenas.patterns[arms[pattern_path.arm_index].patterns[pattern_index]]
671+
let pattern = pattern_path.pattern_index.map(|i| {
672+
arms[pattern_path.arm_index]
673+
.pattern(ctx, i)
674+
.expect("Pattern previously found in arm, but is now missing at index.")
628675
.clone()
629676
});
630-
631677
let lowering_inner_pattern_result = match pattern {
632678
Some(semantic::Pattern::Tuple(patterns)) => patterns
633679
.field_patterns
@@ -664,8 +710,9 @@ fn lower_tuple_match_arm(
664710
.map(|_| ()),
665711
Some(semantic::Pattern::Otherwise(_)) | None => Ok(()),
666712
_ => {
713+
let stable_ptr = pattern.unwrap().stable_ptr();
667714
return Err(LoweringFlowError::Failed(ctx.diagnostics.report(
668-
&pattern.unwrap(),
715+
stable_ptr,
669716
MatchError(MatchError {
670717
kind: match_type,
671718
error: MatchDiagnostic::UnsupportedMatchArmNotATuple,
@@ -685,7 +732,7 @@ fn lower_tuple_match_arm(
685732
fn lower_full_match_tree(
686733
ctx: &mut LoweringContext<'_, '_>,
687734
builder: &mut BlockBuilder,
688-
arms: &[MatchArmWrapper],
735+
arms: &[MatchArmWrapper<'_>],
689736
match_tuple_ctx: &mut LoweringMatchTupleContext,
690737
extracted_enums_details: &[ExtractedEnumDetails],
691738
leaves_builders: &mut Vec<MatchLeafBuilder>,
@@ -775,7 +822,7 @@ pub(crate) fn lower_expr_match_tuple(
775822
expr: LoweredExpr,
776823
matched_expr: semantic::ExprId,
777824
tuple_info: &TupleInfo,
778-
arms: &[MatchArmWrapper],
825+
arms: &[MatchArmWrapper<'_>],
779826
match_type: MatchKind,
780827
) -> LoweringResult<LoweredExpr> {
781828
let location = expr.location();
@@ -897,7 +944,7 @@ pub(crate) fn lower_match_arms(
897944
builder: &mut BlockBuilder,
898945
matched_expr: semantic::ExprId,
899946
lowered_expr: LoweredExpr,
900-
arms: Vec<MatchArmWrapper>,
947+
arms: Vec<MatchArmWrapper<'_>>,
901948
location: LocationId,
902949
match_type: MatchKind,
903950
) -> Result<LoweredExpr, LoweringFlowError> {
@@ -934,7 +981,7 @@ pub(crate) fn lower_concrete_enum_match(
934981
builder: &mut BlockBuilder,
935982
matched_expr: semantic::ExprId,
936983
lowered_matched_expr: LoweredExpr,
937-
arms: &[MatchArmWrapper],
984+
arms: &[MatchArmWrapper<'_>],
938985
location: LocationId,
939986
match_type: MatchKind,
940987
) -> LoweringResult<LoweredExpr> {
@@ -976,7 +1023,8 @@ pub(crate) fn lower_concrete_enum_match(
9761023
let mut subscope = create_subscope(ctx, builder);
9771024

9781025
let pattern = pattern_index.map(|pattern_index| {
979-
&ctx.function_body.arenas.patterns[arm.patterns[pattern_index]]
1026+
arm.pattern(ctx, pattern_index)
1027+
.expect("Pattern was previously found and should be present in the arm.")
9801028
});
9811029
let block_id = subscope.block_id;
9821030
block_ids.push(block_id);
@@ -1005,9 +1053,10 @@ pub(crate) fn lower_concrete_enum_match(
10051053
Pattern::EnumVariant(PatternEnumVariant { inner_pattern: None, .. })
10061054
| Pattern::Otherwise(_),
10071055
) => {
1056+
let location = ctx.get_location(pattern.unwrap().into());
10081057
let var_id = ctx.new_var(VarRequest {
10091058
ty: wrap_in_snapshots(ctx.db, concrete_variant.ty, n_snapshots),
1010-
location: ctx.get_location(pattern.unwrap().into()),
1059+
location,
10111060
});
10121061
arm_var_ids.push(vec![var_id]);
10131062
Ok(())
@@ -1071,7 +1120,7 @@ pub(crate) fn lower_optimized_extern_match(
10711120
ctx: &mut LoweringContext<'_, '_>,
10721121
builder: &mut BlockBuilder,
10731122
extern_enum: LoweredExprExternEnum,
1074-
match_arms: &[MatchArmWrapper],
1123+
match_arms: &[MatchArmWrapper<'_>],
10751124
match_type: MatchKind,
10761125
) -> LoweringResult<LoweredExpr> {
10771126
log::trace!("Started lowering of an optimized extern match.");
@@ -1127,9 +1176,8 @@ pub(crate) fn lower_optimized_extern_match(
11271176
})?;
11281177

11291178
let arm = &match_arms[*arm_index];
1130-
let pattern = pattern_index.map(|pattern_index| {
1131-
&ctx.function_body.arenas.patterns[arm.patterns[pattern_index]]
1132-
});
1179+
let pattern =
1180+
pattern_index.map(|pattern_index| arm.pattern(ctx, pattern_index).unwrap());
11331181

11341182
let lowering_inner_pattern_result = match pattern {
11351183
Some(Pattern::EnumVariant(PatternEnumVariant {
@@ -1197,7 +1245,7 @@ fn group_match_arms(
11971245
ctx: &mut LoweringContext<'_, '_>,
11981246
empty_match_info: MatchInfo,
11991247
location: LocationId,
1200-
arms: &[MatchArmWrapper],
1248+
arms: &[MatchArmWrapper<'_>],
12011249
variants_block_builders: Vec<MatchLeafBuilder>,
12021250
kind: MatchKind,
12031251
) -> LoweringResult<Vec<SealedBlockBuilder>> {
@@ -1220,7 +1268,7 @@ fn group_match_arms(
12201268
return match lowering_inner_pattern_result {
12211269
Ok(_) => {
12221270
// Lower the arm expression.
1223-
match (arm.expr, kind) {
1271+
match (arm.expr(), kind) {
12241272
(Some(expr), MatchKind::IfLet | MatchKind::Match) => {
12251273
lower_tail_expr(ctx, subscope, expr)
12261274
}
@@ -1266,8 +1314,8 @@ fn group_match_arms(
12661314
.map(|(lowering_inner_pattern_result, subscope)| {
12671315
// Use the first pattern for the location of the for variable assignment block.
12681316
let location = arm
1269-
.patterns
1270-
.first()
1317+
.patterns()
1318+
.and_then(|ps| ps.first())
12711319
.map(|pattern| {
12721320
ctx.get_location(
12731321
ctx.function_body.arenas.patterns[*pattern].stable_ptr().untyped(),
@@ -1292,7 +1340,7 @@ fn group_match_arms(
12921340
sealed_blocks,
12931341
location,
12941342
)?;
1295-
match (arm.expr, kind) {
1343+
match (arm.expr(), kind) {
12961344
(Some(expr), MatchKind::IfLet | MatchKind::Match) => {
12971345
lower_tail_expr(ctx, outer_subscope, expr)
12981346
}

crates/cairo-lang-lowering/src/lower/mod.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -365,10 +365,7 @@ pub fn lower_expr_while_let(
365365
)));
366366
}
367367

368-
let arms = vec![
369-
MatchArmWrapper { patterns: patterns.into(), expr: Some(loop_expr.body) },
370-
MatchArmWrapper { patterns: vec![], expr: None },
371-
];
368+
let arms = vec![MatchArmWrapper::Arm(patterns, loop_expr.body), MatchArmWrapper::DefaultClause];
372369

373370
lower_match::lower_match_arms(
374371
ctx,

0 commit comments

Comments
 (0)