harn_parser/typechecker/
exits.rs1use crate::ast::*;
7
8pub fn stmt_definitely_exits(stmt: &SNode) -> bool {
11 match &stmt.node {
12 Node::ReturnStmt { .. } | Node::ThrowStmt { .. } | Node::BreakStmt | Node::ContinueStmt => {
13 true
14 }
15 Node::IfElse {
16 then_body,
17 else_body: Some(else_body),
18 ..
19 } => block_definitely_exits(then_body) && block_definitely_exits(else_body),
20 Node::MatchExpr { arms, .. } => match_definitely_exits(arms),
28 Node::Block(body)
29 | Node::TryExpr { body }
30 | Node::CostRoute { body, .. }
31 | Node::MutexBlock { body }
32 | Node::DeadlineBlock { body, .. }
33 | Node::Retry { body, .. } => block_definitely_exits(body),
34 Node::TryCatch {
35 body,
36 catch_body,
37 finally_body,
38 ..
39 } => {
40 finally_body
41 .as_ref()
42 .is_some_and(|body| block_definitely_exits(body))
43 || (block_definitely_exits(body) && block_definitely_exits(catch_body))
44 }
45 _ => false,
46 }
47}
48
49fn match_definitely_exits(arms: &[MatchArm]) -> bool {
50 if arms.is_empty() {
51 return false;
52 }
53 let has_unguarded_wildcard = arms.iter().any(|arm| {
54 arm.guard.is_none() && matches!(&arm.pattern.node, Node::Identifier(name) if name == "_")
55 });
56 has_unguarded_wildcard && arms.iter().all(|arm| block_definitely_exits(&arm.body))
57}
58
59pub fn block_definitely_exits(stmts: &[SNode]) -> bool {
61 stmts.iter().any(stmt_definitely_exits)
62}