Calls f on every expression under the visited statements. With prune_unreachable, the
arms of &&/||/?: that a literal boolean condition proves unreachable are skipped.
Walks a function body in statement order and, for each loop, flags the EnumerableSet remove
calls that corrupt that loopβs own iteration. The walk keeps, at every point, what each local
storage reference last named, so each loop is judged against the bindings standing where it
runs rather than against every binding of the function.
The storage location a set expression names: a base variable and the steps taken from it.
Two expressions name the same set exactly when they are the same path.
The loopβs own indices that step upward unconditionally: bare identifiers whose every write
on the straight line of the body (bare blocks included) is a supported ascending step. A
reset, a no-op step, a decrement or composite arithmetic disqualifies the variable.
The bare identifier an expression steps upward by one of the simple ascending forms:
i++/++i, i += <positive literal>, i = i + <positive literal> or its commutation.
Whether every statement of a loop body runs on one straight line: no branch, jump, terminal
statement, inline assembly or nested loop (bare blocks are transparent). Any of these could
let control skip a removal or the cadence step, or leave the loop before a shifted slot is
read, none of which this detector tracks.
The variables a statement list writes through expressions, nested loops included:
assignments (tuple targets included), increments, decrements and deletes. Member and indexed
targets do not write their base variable.
The EnumerableSet at or remove a call dispatches to. Resolving through the type checker
covers the using for method form, the library-qualified form and import aliases. The library
is identified only by its kind and exact EnumerableSet name, not its source or behavior.
The path a set expression names, or None when it cannot be read: an index that varies, a
call result, a reference without one straight-line binding, anything the analysis would have
to evaluate.
The user-written body of a loop, peeled out of the synthetic condition guard the lowering
wraps it in: for/while become a single if (cond) { body } else break, do-while appends
if (cond) continue; else break;. Without peeling, the guardβs break/continue would read
as user control flow. A body of another shape is returned unchanged.
What each local storage reference names at the point being analyzed, the latest entry
winning; None marks a reference no straight-line reading gives one answer for.