Skip to content

Commit 7266eea

Browse files
committed
flow_control: Add diagnostics for unreachable arms.
1 parent 184d7c2 commit 7266eea

File tree

6 files changed

+121
-29
lines changed

6 files changed

+121
-29
lines changed

crates/cairo-lang-lowering/src/diagnostic.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ impl<'db> MatchError<'db> {
173173
"Unreachable pattern arm.".into()
174174
}
175175
(MatchDiagnostic::UnreachableMatchArm, MatchKind::IfLet) => {
176-
"Unreachable else clause.".into()
176+
"Unreachable clause.".into()
177177
}
178178
(MatchDiagnostic::UnreachableMatchArm, MatchKind::WhileLet(_, _)) => {
179179
unreachable!("While-let does not have two arms.")

crates/cairo-lang-lowering/src/lower/flow_control/create_graph.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use super::graph::{
99
ArmExpr, BooleanIf, EvaluateExpr, FlowControlGraph, FlowControlGraphBuilder, FlowControlNode,
1010
NodeId,
1111
};
12-
use crate::lower::context::LoweringContext;
12+
use crate::{diagnostic::MatchKind, lower::context::LoweringContext};
1313

1414
mod cache;
1515
mod filtered_patterns;
@@ -20,7 +20,7 @@ pub fn create_graph_expr_if<'db>(
2020
ctx: &mut LoweringContext<'db, '_>,
2121
expr: &semantic::ExprIf<'db>,
2222
) -> FlowControlGraph<'db> {
23-
let mut graph = FlowControlGraphBuilder::default();
23+
let mut graph = FlowControlGraphBuilder::new(MatchKind::IfLet);
2424

2525
// Add the `true` branch (the `if` block).
2626
let true_branch = graph.add_node(FlowControlNode::ArmExpr(ArmExpr { expr: expr.if_block }));
@@ -111,7 +111,7 @@ pub fn create_graph_expr_match<'db>(
111111
ctx: &mut LoweringContext<'db, '_>,
112112
expr: &semantic::ExprMatch<'db>,
113113
) -> FlowControlGraph<'db> {
114-
let mut graph = FlowControlGraphBuilder::default();
114+
let mut graph = FlowControlGraphBuilder::new(MatchKind::Match);
115115

116116
let matched_expr = &ctx.function_body.arenas.exprs[expr.matched_expr];
117117
let matched_expr_location = ctx.get_location(matched_expr.stable_ptr().untyped());

crates/cairo-lang-lowering/src/lower/flow_control/graph.rs

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use cairo_lang_utils::unordered_hash_set::UnorderedHashSet;
2929
use itertools::Itertools;
3030

3131
use crate::diagnostic::{
32-
LoweringDiagnosticKind, LoweringDiagnostics, LoweringDiagnosticsBuilder,
32+
LoweringDiagnosticKind, LoweringDiagnostics, LoweringDiagnosticsBuilder, MatchKind,
3333
};
3434
use crate::ids::LocationId;
3535
use crate::lower::context::LoweringContext;
@@ -234,6 +234,9 @@ pub struct FlowControlGraph<'db> {
234234
var_locations: Vec<LocationId<'db>>,
235235
/// The pattern variables used by the [BindVar] nodes in the graph.
236236
pattern_vars: Vec<PatternVariable<'db>>,
237+
/// The kind of the expression being lowered.
238+
/// This is used for diagnostic reporting.
239+
kind: MatchKind<'db>,
237240
}
238241
impl<'db> FlowControlGraph<'db> {
239242
/// Returns the root node of the graph.
@@ -251,6 +254,11 @@ impl<'db> FlowControlGraph<'db> {
251254
pub fn node(&self, id: NodeId) -> &FlowControlNode<'db> {
252255
&self.nodes[id.0]
253256
}
257+
258+
/// Returns the kind of the expression being lowered.
259+
pub fn kind(&self) -> MatchKind<'db> {
260+
self.kind
261+
}
254262
}
255263

256264
impl<'db> Debug for FlowControlGraph<'db> {
@@ -271,6 +279,22 @@ pub struct FlowControlGraphBuilder<'db> {
271279
}
272280

273281
impl<'db> FlowControlGraphBuilder<'db> {
282+
/// Constructs a new [FlowControlGraphBuilder].
283+
pub fn new(kind: MatchKind<'db>) -> Self {
284+
let graph = FlowControlGraph {
285+
nodes: Vec::new(),
286+
var_types: Vec::new(),
287+
var_locations: Vec::new(),
288+
pattern_vars: Vec::new(),
289+
kind,
290+
};
291+
Self {
292+
graph,
293+
used_vars: UnorderedHashSet::default(),
294+
diagnostics: LoweringDiagnostics::default(),
295+
}
296+
}
297+
274298
/// Adds a new node to the graph. Returns the new node's id.
275299
pub fn add_node(&mut self, node: FlowControlNode<'db>) -> NodeId {
276300
// Mark the input variable (if exists) as used.
@@ -334,19 +358,3 @@ impl<'db> FlowControlGraphBuilder<'db> {
334358
self.diagnostics.report(stable_ptr, kind)
335359
}
336360
}
337-
338-
impl<'db> Default for FlowControlGraphBuilder<'db> {
339-
fn default() -> Self {
340-
let graph = FlowControlGraph {
341-
nodes: Vec::new(),
342-
var_types: Vec::new(),
343-
var_locations: Vec::new(),
344-
pattern_vars: Vec::new(),
345-
};
346-
Self {
347-
graph,
348-
used_vars: UnorderedHashSet::default(),
349-
diagnostics: LoweringDiagnostics::default(),
350-
}
351-
}
352-
}

crates/cairo-lang-lowering/src/lower/flow_control/lower_graph/lower_node.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use cairo_lang_syntax::node::TypedStablePtr;
66
use itertools::zip_eq;
77

88
use super::LowerGraphContext;
9+
use crate::diagnostic::{LoweringDiagnosticKind, LoweringDiagnosticsBuilder, MatchDiagnostic, MatchError};
910
use crate::ids::SemanticFunctionIdEx;
1011
use crate::lower::block_builder::BlockBuilder;
1112
use crate::lower::context::{LoweredExpr, VarRequest};
@@ -22,6 +23,18 @@ use crate::{MatchArm, MatchEnumInfo, MatchExternInfo, MatchInfo, VarUsage};
2223
/// Lowers the node with the given [NodeId].
2324
pub fn lower_node(ctx: &mut LowerGraphContext<'_, '_, '_>, id: NodeId) -> Maybe<()> {
2425
let Some(builder) = ctx.get_builder_if_reachable(id) else {
26+
// If an [ArmExpr] node is unreachable, report an error.
27+
// TODO(lior): If the main branch is unreachable, report an proper error.
28+
if let FlowControlNode::ArmExpr(node) = ctx.graph.node(id) {
29+
let stable_ptr = ctx.ctx.function_body.arenas.exprs[node.expr].stable_ptr();
30+
31+
let match_error = LoweringDiagnosticKind::MatchError(MatchError{
32+
kind: ctx.graph.kind(),
33+
error: MatchDiagnostic::UnreachableMatchArm,
34+
});
35+
ctx.ctx.diagnostics.report(stable_ptr, match_error);
36+
}
37+
2538
return Ok(());
2639
};
2740

crates/cairo-lang-lowering/src/lower/flow_control/test_data/if

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ End:
306306
//! > Test if with panic in condition
307307

308308
//! > test_runner_name
309-
test_create_graph(expect_diagnostics: false)
309+
test_create_graph(expect_diagnostics: true)
310310

311311
//! > function_code
312312
fn foo() -> felt252 {
@@ -329,6 +329,21 @@ Root: 3
329329
//! > semantic_diagnostics
330330

331331
//! > lowering_diagnostics
332+
warning: Unreachable clause.
333+
--> lib.cairo:4:12-6:5
334+
} else {
335+
____________^
336+
| 1
337+
| }
338+
|_____^
339+
340+
warning: Unreachable clause.
341+
--> lib.cairo:2:17-4:5
342+
if panic!() {
343+
_________________^
344+
| 0
345+
| } else {
346+
|_____^
332347

333348
//! > lowered
334349
Parameters:
@@ -547,7 +562,7 @@ End:
547562
//! > Test if let-chain with panic in condition
548563

549564
//! > test_runner_name
550-
test_create_graph(expect_diagnostics: false)
565+
test_create_graph(expect_diagnostics: true)
551566

552567
//! > function_code
553568
fn foo() -> felt252 {
@@ -572,6 +587,13 @@ Root: 5
572587
//! > semantic_diagnostics
573588

574589
//! > lowering_diagnostics
590+
warning: Unreachable clause.
591+
--> lib.cairo:2:42-4:5
592+
if let Some(_) = Some(0) && panic!() {
593+
__________________________________________^
594+
| 0
595+
| } else {
596+
|_____^
575597

576598
//! > lowered
577599
Parameters:
@@ -607,3 +629,46 @@ blk3:
607629
Statements:
608630
End:
609631
Return(v12)
632+
633+
//! > ==========================================================================
634+
635+
//! > Unreachable else clause.
636+
637+
//! > test_runner_name
638+
test_create_graph(expect_diagnostics: true)
639+
640+
//! > function_code
641+
fn foo(x: Option<felt252>) -> felt252 {
642+
if let Some(_) | None = x {
643+
0
644+
} else {
645+
1
646+
}
647+
}
648+
649+
//! > module_code
650+
651+
//! > graph
652+
Root: 2
653+
0 ArmExpr { expr: ExprId(2) }
654+
1 ArmExpr { expr: ExprId(4) }
655+
2 EvaluateExpr { expr: ExprId(0), var_id: v0, next: NodeId(0) }
656+
657+
//! > semantic_diagnostics
658+
659+
//! > lowering_diagnostics
660+
warning: Unreachable clause.
661+
--> lib.cairo:4:12-6:5
662+
} else {
663+
____________^
664+
| 1
665+
| }
666+
|_____^
667+
668+
//! > lowered
669+
Parameters: v0: core::option::Option::<core::felt252>
670+
blk0 (root):
671+
Statements:
672+
(v1: core::felt252) <- 0
673+
End:
674+
Return(v1)

crates/cairo-lang-lowering/src/lower/flow_control/test_data/match

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
//! > Simple match
22

33
//! > test_runner_name
4-
test_create_graph(expect_diagnostics: false)
4+
test_create_graph(expect_diagnostics: true)
55

66
//! > function_code
77
fn foo(color: Color) -> felt252 {
88
match color {
99
Color::Red | Color::Green(_) => 1,
1010
Color::Red(_) | Color::Blue => 2,
11-
_ => 3,
11+
Color::Blue | Color::Green => 3,
12+
_ => 4,
1213
}
1314
}
1415

@@ -22,16 +23,21 @@ enum Color {
2223
}
2324

2425
//! > graph
25-
Root: 4
26+
Root: 5
2627
0 ArmExpr { expr: ExprId(1) }
2728
1 ArmExpr { expr: ExprId(2) }
2829
2 ArmExpr { expr: ExprId(3) }
29-
3 EnumMatch { matched_var: v0, variants: (NodeId(0), v1), (NodeId(0), v2), (NodeId(1), v3), (NodeId(2), v4), (NodeId(2), v5)}
30-
4 EvaluateExpr { expr: ExprId(0), var_id: v0, next: NodeId(3) }
30+
3 ArmExpr { expr: ExprId(4) }
31+
4 EnumMatch { matched_var: v0, variants: (NodeId(0), v1), (NodeId(0), v2), (NodeId(1), v3), (NodeId(3), v4), (NodeId(3), v5)}
32+
5 EvaluateExpr { expr: ExprId(0), var_id: v0, next: NodeId(4) }
3133

3234
//! > semantic_diagnostics
3335

3436
//! > lowering_diagnostics
37+
warning: Unreachable pattern arm.
38+
--> lib.cairo:12:39
39+
Color::Blue | Color::Green => 3,
40+
^
3541

3642
//! > lowered
3743
Parameters: v0: test::Color
@@ -74,7 +80,7 @@ End:
7480

7581
blk6:
7682
Statements:
77-
(v6: core::felt252) <- 3
83+
(v6: core::felt252) <- 4
7884
End:
7985
Goto(blk8, {v6 -> v9})
8086

0 commit comments

Comments
 (0)