phase29an(p1): add loop feature facts ssot (exit usage)

This commit is contained in:
2025-12-29 17:43:19 +09:00
parent 134a0d2f7d
commit c7fbcf3c86
4 changed files with 134 additions and 0 deletions

View File

@ -0,0 +1,119 @@
//! Phase 29an P1: FeatureFacts SSOT (ExitUsage placeholders)
use crate::ast::ASTNode;
use crate::mir::builder::control_flow::plan::planner::Freeze;
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub(in crate::mir::builder) struct ExitUsageFacts {
pub has_break: bool,
pub has_continue: bool,
pub has_return: bool,
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub(in crate::mir::builder) struct LoopFeatureFacts {
pub exit_usage: ExitUsageFacts,
pub value_join: Option<ValueJoinFacts>,
pub cleanup: Option<CleanupFacts>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(in crate::mir::builder) struct ValueJoinFacts;
#[derive(Debug, Clone, PartialEq, Eq)]
pub(in crate::mir::builder) struct CleanupFacts;
pub(in crate::mir::builder) fn try_extract_loop_feature_facts(
body: &[ASTNode],
) -> Result<LoopFeatureFacts, Freeze> {
let mut exit_usage = ExitUsageFacts::default();
for stmt in body {
update_exit_usage_from_stmt(stmt, &mut exit_usage);
}
Ok(LoopFeatureFacts {
exit_usage,
value_join: None,
cleanup: None,
})
}
fn update_exit_usage_from_stmt(stmt: &ASTNode, usage: &mut ExitUsageFacts) {
match stmt {
ASTNode::Break { .. } => usage.has_break = true,
ASTNode::Continue { .. } => usage.has_continue = true,
ASTNode::Return { .. } => usage.has_return = true,
ASTNode::If {
then_body,
else_body,
..
} => {
for nested in then_body {
update_exit_usage_from_stmt(nested, usage);
}
if let Some(else_body) = else_body {
for nested in else_body {
update_exit_usage_from_stmt(nested, usage);
}
}
}
ASTNode::Loop { .. }
| ASTNode::While { .. }
| ASTNode::ForRange { .. } => {}
_ => {}
}
}
#[cfg(test)]
mod tests {
use super::{try_extract_loop_feature_facts, ExitUsageFacts};
use crate::ast::{ASTNode, LiteralValue, Span};
fn lit_bool(value: bool) -> ASTNode {
ASTNode::Literal {
value: LiteralValue::Bool(value),
span: Span::unknown(),
}
}
#[test]
fn exit_usage_tracks_break_continue_return_in_if() {
let body = vec![
ASTNode::If {
condition: Box::new(lit_bool(true)),
then_body: vec![ASTNode::Break {
span: Span::unknown(),
}],
else_body: Some(vec![ASTNode::Continue {
span: Span::unknown(),
}]),
span: Span::unknown(),
},
ASTNode::Return {
value: None,
span: Span::unknown(),
},
];
let facts = try_extract_loop_feature_facts(&body).expect("Ok");
assert_eq!(
facts.exit_usage,
ExitUsageFacts {
has_break: true,
has_continue: true,
has_return: true,
}
);
}
#[test]
fn exit_usage_ignores_nested_loops() {
let nested = ASTNode::Loop {
condition: Box::new(lit_bool(true)),
body: vec![ASTNode::Break {
span: Span::unknown(),
}],
span: Span::unknown(),
};
let facts = try_extract_loop_feature_facts(&[nested]).expect("Ok");
assert_eq!(facts.exit_usage, ExitUsageFacts::default());
}
}

View File

@ -37,12 +37,14 @@ use super::pattern2_loopbodylocal_facts::{
Pattern2LoopBodyLocalFacts, try_extract_pattern2_loopbodylocal_facts,
};
use super::skeleton_facts::{SkeletonFacts, try_extract_loop_skeleton_facts};
use super::feature_facts::{LoopFeatureFacts, try_extract_loop_feature_facts};
#[derive(Debug, Clone)]
pub(in crate::mir::builder) struct LoopFacts {
pub condition_shape: ConditionShape,
pub step_shape: StepShape,
pub skeleton: Option<SkeletonFacts>,
pub features: Option<LoopFeatureFacts>,
pub scan_with_init: Option<ScanWithInitFacts>,
pub split_scan: Option<SplitScanFacts>,
pub pattern1_simplewhile: Option<Pattern1SimpleWhileFacts>,
@ -145,11 +147,13 @@ fn try_build_loop_facts_inner(
}
let skeleton = try_extract_loop_skeleton_facts(condition, body)?;
let features = Some(try_extract_loop_feature_facts(body)?);
Ok(Some(LoopFacts {
condition_shape,
step_shape,
skeleton,
features,
scan_with_init,
split_scan,
pattern1_simplewhile,

View File

@ -7,6 +7,7 @@
#![allow(dead_code)]
pub(in crate::mir::builder) mod loop_facts;
pub(in crate::mir::builder) mod feature_facts;
pub(in crate::mir::builder) mod pattern1_simplewhile_facts;
pub(in crate::mir::builder) mod pattern3_ifphi_facts;
pub(in crate::mir::builder) mod pattern4_continue_facts;

View File

@ -249,6 +249,7 @@ mod tests {
condition_shape: ConditionShape::Unknown,
step_shape: StepShape::Unknown,
skeleton: None,
features: None,
scan_with_init: None,
split_scan: Some(SplitScanFacts {
s_var: "s".to_string(),
@ -287,6 +288,7 @@ mod tests {
condition_shape: ConditionShape::Unknown,
step_shape: StepShape::Unknown,
skeleton: None,
features: None,
scan_with_init: None,
split_scan: None,
pattern1_simplewhile: None,
@ -309,6 +311,7 @@ mod tests {
condition_shape: ConditionShape::Unknown,
step_shape: StepShape::Unknown,
skeleton: None,
features: None,
scan_with_init: Some(ScanWithInitFacts {
loop_var: "i".to_string(),
haystack: "s".to_string(),
@ -354,6 +357,7 @@ mod tests {
condition_shape: ConditionShape::Unknown,
step_shape: StepShape::Unknown,
skeleton: None,
features: None,
scan_with_init: None,
split_scan: None,
pattern1_simplewhile: Some(Pattern1SimpleWhileFacts {
@ -417,6 +421,7 @@ mod tests {
condition_shape: ConditionShape::Unknown,
step_shape: StepShape::Unknown,
skeleton: None,
features: None,
scan_with_init: None,
split_scan: None,
pattern1_simplewhile: None,
@ -479,6 +484,7 @@ mod tests {
condition_shape: ConditionShape::Unknown,
step_shape: StepShape::Unknown,
skeleton: None,
features: None,
scan_with_init: None,
split_scan: None,
pattern1_simplewhile: None,
@ -527,6 +533,7 @@ mod tests {
condition_shape: ConditionShape::Unknown,
step_shape: StepShape::Unknown,
skeleton: None,
features: None,
scan_with_init: None,
split_scan: None,
pattern1_simplewhile: None,
@ -576,6 +583,7 @@ mod tests {
condition_shape: ConditionShape::Unknown,
step_shape: StepShape::Unknown,
skeleton: None,
features: None,
scan_with_init: None,
split_scan: None,
pattern1_simplewhile: None,
@ -633,6 +641,7 @@ mod tests {
condition_shape: ConditionShape::Unknown,
step_shape: StepShape::Unknown,
skeleton: None,
features: None,
scan_with_init: None,
split_scan: None,
pattern1_simplewhile: None,
@ -696,6 +705,7 @@ mod tests {
condition_shape: ConditionShape::Unknown,
step_shape: StepShape::Unknown,
skeleton: None,
features: None,
scan_with_init: None,
split_scan: None,
pattern1_simplewhile: None,