@@ -275,7 +275,61 @@ fn collect_op_fences(op: &UpdateOp<'_>) -> Fence {
275275 UpdateOp :: Control ( ctrl) => collect_fences ( & ctrl. expression ) ,
276276 UpdateOp :: I18nExpression ( i18n) => collect_fences ( & i18n. expression ) ,
277277 UpdateOp :: DeferWhen ( defer_when) => collect_fences ( & defer_when. condition ) ,
278- UpdateOp :: Statement ( _) => Fence :: NONE ,
278+ UpdateOp :: Statement ( stmt) => collect_fences_in_output_statement ( & stmt. statement ) ,
279+ _ => Fence :: NONE ,
280+ }
281+ }
282+
283+ /// Collect fences from an OutputStatement.
284+ fn collect_fences_in_output_statement ( stmt : & OutputStatement < ' _ > ) -> Fence {
285+ match stmt {
286+ OutputStatement :: Expression ( expr_stmt) => {
287+ collect_fences_in_output_expression ( & expr_stmt. expr )
288+ }
289+ OutputStatement :: If ( if_stmt) => {
290+ let mut fences = collect_fences_in_output_expression ( & if_stmt. condition ) ;
291+ for s in if_stmt. true_case . iter ( ) {
292+ fences |= collect_fences_in_output_statement ( s) ;
293+ }
294+ for s in if_stmt. false_case . iter ( ) {
295+ fences |= collect_fences_in_output_statement ( s) ;
296+ }
297+ fences
298+ }
299+ OutputStatement :: Return ( ret) => collect_fences_in_output_expression ( & ret. value ) ,
300+ _ => Fence :: NONE ,
301+ }
302+ }
303+
304+ /// Collect fences from an OutputExpression.
305+ fn collect_fences_in_output_expression ( expr : & OutputExpression < ' _ > ) -> Fence {
306+ match expr {
307+ OutputExpression :: WrappedIrNode ( wrapped) => collect_fences ( & wrapped. node ) ,
308+ OutputExpression :: BinaryOperator ( bin) => {
309+ collect_fences_in_output_expression ( & bin. lhs )
310+ | collect_fences_in_output_expression ( & bin. rhs )
311+ }
312+ OutputExpression :: Conditional ( cond) => {
313+ let mut fences = collect_fences_in_output_expression ( & cond. condition ) ;
314+ fences |= collect_fences_in_output_expression ( & cond. true_case ) ;
315+ if let Some ( ref false_case) = cond. false_case {
316+ fences |= collect_fences_in_output_expression ( false_case) ;
317+ }
318+ fences
319+ }
320+ OutputExpression :: InvokeFunction ( call) => {
321+ let mut fences = collect_fences_in_output_expression ( & call. fn_expr ) ;
322+ for arg in call. args . iter ( ) {
323+ fences |= collect_fences_in_output_expression ( arg) ;
324+ }
325+ fences
326+ }
327+ OutputExpression :: Not ( unary) => collect_fences_in_output_expression ( & unary. condition ) ,
328+ OutputExpression :: ReadProp ( prop) => collect_fences_in_output_expression ( & prop. receiver ) ,
329+ OutputExpression :: ReadKey ( keyed) => {
330+ collect_fences_in_output_expression ( & keyed. receiver )
331+ | collect_fences_in_output_expression ( & keyed. index )
332+ }
279333 _ => Fence :: NONE ,
280334 }
281335}
@@ -1224,6 +1278,9 @@ where
12241278 UpdateOp :: DeferWhen ( defer_when) => {
12251279 visit_all_expressions ( & defer_when. condition , & mut visitor)
12261280 }
1281+ UpdateOp :: Statement ( stmt) => {
1282+ visit_ir_expressions_in_output_statement ( & stmt. statement , & mut visitor) ;
1283+ }
12271284 _ => { }
12281285 }
12291286}
@@ -1356,6 +1413,86 @@ where
13561413 }
13571414}
13581415
1416+ /// Visit IR expressions inside an OutputStatement.
1417+ ///
1418+ /// Statement ops are created by `convert_variables_to_statements` when unused
1419+ /// side-effectful variables (like StoreLet) are converted from Variable ops to
1420+ /// standalone expression statements. The IR expressions inside these statements
1421+ /// still contain ReadVariable references that must be counted for correct
1422+ /// context variable inlining decisions.
1423+ fn visit_ir_expressions_in_output_statement < F > ( stmt : & OutputStatement < ' _ > , visitor : & mut F )
1424+ where
1425+ F : FnMut ( & IrExpression < ' _ > ) ,
1426+ {
1427+ match stmt {
1428+ OutputStatement :: Expression ( expr_stmt) => {
1429+ visit_ir_expressions_in_output_expression ( & expr_stmt. expr , visitor) ;
1430+ }
1431+ OutputStatement :: If ( if_stmt) => {
1432+ visit_ir_expressions_in_output_expression ( & if_stmt. condition , visitor) ;
1433+ for s in if_stmt. true_case . iter ( ) {
1434+ visit_ir_expressions_in_output_statement ( s, visitor) ;
1435+ }
1436+ for s in if_stmt. false_case . iter ( ) {
1437+ visit_ir_expressions_in_output_statement ( s, visitor) ;
1438+ }
1439+ }
1440+ OutputStatement :: Return ( ret) => {
1441+ visit_ir_expressions_in_output_expression ( & ret. value , visitor) ;
1442+ }
1443+ _ => { }
1444+ }
1445+ }
1446+
1447+ /// Visit IR expressions inside an OutputExpression.
1448+ ///
1449+ /// Traverses OutputExpression tree to find WrappedIrNode nodes which contain
1450+ /// actual IR expressions that may reference variables.
1451+ fn visit_ir_expressions_in_output_expression < F > ( expr : & OutputExpression < ' _ > , visitor : & mut F )
1452+ where
1453+ F : FnMut ( & IrExpression < ' _ > ) ,
1454+ {
1455+ match expr {
1456+ OutputExpression :: WrappedIrNode ( wrapped) => {
1457+ visit_all_expressions ( & wrapped. node , visitor) ;
1458+ }
1459+ OutputExpression :: BinaryOperator ( bin) => {
1460+ visit_ir_expressions_in_output_expression ( & bin. lhs , visitor) ;
1461+ visit_ir_expressions_in_output_expression ( & bin. rhs , visitor) ;
1462+ }
1463+ OutputExpression :: Conditional ( cond) => {
1464+ visit_ir_expressions_in_output_expression ( & cond. condition , visitor) ;
1465+ visit_ir_expressions_in_output_expression ( & cond. true_case , visitor) ;
1466+ if let Some ( ref false_case) = cond. false_case {
1467+ visit_ir_expressions_in_output_expression ( false_case, visitor) ;
1468+ }
1469+ }
1470+ OutputExpression :: InvokeFunction ( call) => {
1471+ visit_ir_expressions_in_output_expression ( & call. fn_expr , visitor) ;
1472+ for arg in call. args . iter ( ) {
1473+ visit_ir_expressions_in_output_expression ( arg, visitor) ;
1474+ }
1475+ }
1476+ OutputExpression :: Not ( unary) => {
1477+ visit_ir_expressions_in_output_expression ( & unary. condition , visitor) ;
1478+ }
1479+ OutputExpression :: Instantiate ( inst) => {
1480+ visit_ir_expressions_in_output_expression ( & inst. class_expr , visitor) ;
1481+ for arg in inst. args . iter ( ) {
1482+ visit_ir_expressions_in_output_expression ( arg, visitor) ;
1483+ }
1484+ }
1485+ OutputExpression :: ReadProp ( prop) => {
1486+ visit_ir_expressions_in_output_expression ( & prop. receiver , visitor) ;
1487+ }
1488+ OutputExpression :: ReadKey ( keyed) => {
1489+ visit_ir_expressions_in_output_expression ( & keyed. receiver , visitor) ;
1490+ visit_ir_expressions_in_output_expression ( & keyed. index , visitor) ;
1491+ }
1492+ _ => { }
1493+ }
1494+ }
1495+
13591496/// Result of collecting variables that need to be processed.
13601497struct VariableActions {
13611498 /// Variables that should be completely removed (unused, not side-effectful).
0 commit comments