@@ -22,14 +22,19 @@ impl<'a> TransformCtx<'a> {
2222 /// * Unbound identifier `foo` -> `_foo = foo`, `_foo`
2323 /// * Anything else `foo()` -> `_foo = foo()`, `_foo`
2424 ///
25+ /// If `mutated_symbol_needs_temp_var` is `true`, temp var will be created for a bound identifier,
26+ /// if it's mutated (assigned to) anywhere in AST.
27+ ///
2528 /// Returns 2 `Expression`s. The first may be an `AssignmentExpression`,
2629 /// and must be inserted into output first.
2730 pub ( crate ) fn duplicate_expression (
2831 & self ,
2932 expr : Expression < ' a > ,
33+ mutated_symbol_needs_temp_var : bool ,
3034 ctx : & mut TraverseCtx < ' a > ,
3135 ) -> ( Expression < ' a > , Expression < ' a > ) {
32- let ( maybe_assignment, references) = self . duplicate_expression_multiple :: < 1 > ( expr, ctx) ;
36+ let ( maybe_assignment, references) =
37+ self . duplicate_expression_multiple :: < 1 > ( expr, mutated_symbol_needs_temp_var, ctx) ;
3338 let [ reference] = references;
3439 ( maybe_assignment, reference)
3540 }
@@ -43,15 +48,20 @@ impl<'a> TransformCtx<'a> {
4348 /// * Unbound identifier `foo` -> `_foo = foo`, `_foo`, `_foo`
4449 /// * Anything else `foo()` -> `_foo = foo()`, `_foo`, `_foo`
4550 ///
51+ /// If `mutated_symbol_needs_temp_var` is `true`, temp var will be created for a bound identifier,
52+ /// if it's mutated (assigned to) anywhere in AST.
53+ ///
4654 /// Returns 3 `Expression`s. The first may be an `AssignmentExpression`,
4755 /// and must be inserted into output first.
4856 #[ expect( clippy:: similar_names) ]
4957 pub ( crate ) fn duplicate_expression_twice (
5058 & self ,
5159 expr : Expression < ' a > ,
60+ mutated_symbol_needs_temp_var : bool ,
5261 ctx : & mut TraverseCtx < ' a > ,
5362 ) -> ( Expression < ' a > , Expression < ' a > , Expression < ' a > ) {
54- let ( maybe_assignment, references) = self . duplicate_expression_multiple :: < 2 > ( expr, ctx) ;
63+ let ( maybe_assignment, references) =
64+ self . duplicate_expression_multiple :: < 2 > ( expr, mutated_symbol_needs_temp_var, ctx) ;
5565 let [ reference1, reference2] = references;
5666 ( maybe_assignment, reference1, reference2)
5767 }
@@ -65,26 +75,36 @@ impl<'a> TransformCtx<'a> {
6575 /// * Unbound identifier `foo` -> `_foo = foo`, [`_foo`; N]
6676 /// * Anything else `foo()` -> `_foo = foo()`, [`_foo`; N]
6777 ///
78+ /// If `mutated_symbol_needs_temp_var` is `true`, temp var will be created for a bound identifier,
79+ /// if it's mutated (assigned to) anywhere in AST.
80+ ///
6881 /// Returns `N + 1` x `Expression`s. The first may be an `AssignmentExpression`,
6982 /// and must be inserted into output first.
7083 pub ( crate ) fn duplicate_expression_multiple < const N : usize > (
7184 & self ,
7285 expr : Expression < ' a > ,
86+ mutated_symbol_needs_temp_var : bool ,
7387 ctx : & mut TraverseCtx < ' a > ,
7488 ) -> ( Expression < ' a > , [ Expression < ' a > ; N ] ) {
7589 // TODO: Handle if in a function's params
7690 let temp_var_binding = match & expr {
7791 Expression :: Identifier ( ident) => {
78- let reference = ctx. symbols_mut ( ) . get_reference_mut ( ident. reference_id ( ) ) ;
92+ let reference_id = ident. reference_id ( ) ;
93+ let reference = ctx. symbols ( ) . get_reference ( reference_id) ;
7994 if let Some ( symbol_id) = reference. symbol_id ( ) {
80- // Reading bound identifier cannot have side effects, so no need for temp var
81- let binding = BoundIdentifier :: new ( ident. name . clone ( ) , symbol_id) ;
82- let references =
83- create_array ( || binding. create_spanned_read_expression ( ident. span , ctx) ) ;
84- return ( expr, references) ;
95+ if !mutated_symbol_needs_temp_var || !ctx. symbols ( ) . symbol_is_mutated ( symbol_id)
96+ {
97+ // Reading bound identifier cannot have side effects, so no need for temp var
98+ let binding = BoundIdentifier :: new ( ident. name . clone ( ) , symbol_id) ;
99+ let references = create_array ( || {
100+ binding. create_spanned_read_expression ( ident. span , ctx)
101+ } ) ;
102+ return ( expr, references) ;
103+ }
85104 }
86105
87106 // Previously `x += 1` (`x` read + write), but moving to `_x = x` (`x` read only)
107+ let reference = ctx. symbols_mut ( ) . get_reference_mut ( reference_id) ;
88108 * reference. flags_mut ( ) = ReferenceFlags :: Read ;
89109
90110 self . var_declarations . create_uid_var ( & ident. name , ctx)
0 commit comments