Compute the assignment dependency depth for a loop body. Does a cheap AST walk (no type resolution) to find which variables are assigned and which other variables appear on the RHS. Then follows the dependency chain to compute the longest path. For example, in: $a = $input; $b = transform($a); $c = $b + 1; The dependency map is {$a → {$input}, $b → {$a}, $c → {$b}} and the longest chain is 3 (
(statements: &[&Statement<'_>])
| 5804 | /// This determines how many loop iterations are needed for types to |
| 5805 | /// propagate through the entire chain. Typically 1-3 for real PHP. |
| 5806 | fn assignment_map_depth(statements: &[&Statement<'_>]) -> u32 { |
| 5807 | // Build dependency map: assigned_var → set of RHS variables |
| 5808 | let mut deps: HashMap<String, HashSet<String>> = HashMap::new(); |
| 5809 | |
| 5810 | for stmt in statements { |
| 5811 | collect_assignment_deps(stmt, &mut deps); |
| 5812 | } |
| 5813 | |
| 5814 | if deps.is_empty() { |
| 5815 | return 1; |
| 5816 | } |
| 5817 | |
| 5818 | // Compute longest dependency chain via DFS with cycle detection. |
| 5819 | let mut cache: HashMap<String, u32> = HashMap::new(); |
| 5820 | let mut max_depth: u32 = 1; |
| 5821 | let keys: Vec<String> = deps.keys().cloned().collect(); |
| 5822 | for key in &keys { |
| 5823 | let d = chain_depth(key, &deps, &mut cache, &mut HashSet::new()); |
| 5824 | max_depth = max_depth.max(d); |
| 5825 | } |
| 5826 | |
| 5827 | // The chain depth tells us how many levels of variable-to-variable |
| 5828 | // propagation exist. But even a single assignment needs 2 iterations: |
| 5829 | // one to discover the assignment, one to re-walk with the discovered |
| 5830 | // type visible from the start. So: iterations = depth + 1. |
| 5831 | // Clamp to a reasonable maximum to avoid pathological cases. |
| 5832 | (max_depth + 1).min(3) |
| 5833 | } |
| 5834 | |
| 5835 | /// Recursively compute the dependency chain depth for a variable. |
| 5836 | fn chain_depth( |
no test coverage detected