loopEntryDepths property
How deep each loop stack was when a for loop was entered.
WHY. Leaving a loop — at its end, or by break / continue from inside
it — must remove exactly what it and the loops nested in it pushed, and
the stacks cannot answer that themselves: they are not parallel. A for-in
over an existing variable pushes a node and no environment, a for-in
that declares one pushes its environment only on the first element, and
only a classic for pushes an initialisation flag. Popping "the last
entry" of each, which break used to do, left the wrong loop whenever
those shapes were nested. Recording the depths on entry makes the exit
exact whatever was pushed in between.
Keyed by identity: the node is the loop, not a structurally equal one.
Implementation
final Map<SAstNode, LoopStackDepths> loopEntryDepths = Map.identity();