Skip to main content

Module mutation

Module mutation 

Source
Expand description

Mutation detection with escape analysis for Python — the fxrank-lang-python analog of fxrank-lang-ts’s detect/mutation.rs.

Python’s mutation story is simpler than Rust’s (no &mut / ownership) but more nuanced than JS’s: global and nonlocal declarations are function-wide (not position-dependent), and self.attr = … inside __init__ is construction (contained), not escaping state mutation.

§Escape classification table

write sitekindclasscontained
global x declared, then x = … or x += …global.mutation6false
nonlocal x declared, then x = … or x += …this.mutation3false
self.attr = … in __init__local.mutation1true
self.attr = … in a non-__init__ methodthis.mutation3false
self.x.append(…) / self[i] = … (any method, incl. __init__)this.mutation3false
write where root is a param nameparam.mutation3false
write where root is a local bindinglocal.mutation1true
module top-level binding, content-mutated (no global)global.mutation6false

§Strategy

  1. Pre-scan the function body for global/nonlocal declarations and local bindings — Assign/AnnAssign targets (incl. tuple/list/starred destructuring), AugAssign bare-Name targets, for/async for loop targets, with … as/async with … as names, and except … as / except* … as names — building the globals, nonlocals, and locals sets. (Python scoping: any binding-form in a body makes the name function-local for the whole function.)
  2. Extract parameter names from unit.params.
  3. Walk the body classifying write targets: Assign/AnnAssign/AugAssign targets, and mutating method calls (.append, .update, .add) via on_call in the EffectSink.

The contained bool returned alongside each Effect is the boundary-containment signal that Task 9’s discount consumes.

Functions§

detect
Detect mutation effects in unit’s own body, with escape analysis.