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 site | kind | class | contained |
|---|---|---|---|
global x declared, then x = … or x += … | global.mutation | 6 | false |
nonlocal x declared, then x = … or x += … | this.mutation | 3 | false |
self.attr = … in __init__ | local.mutation | 1 | true |
self.attr = … in a non-__init__ method | this.mutation | 3 | false |
self.x.append(…) / self[i] = … (any method, incl. __init__) | this.mutation | 3 | false |
| write where root is a param name | param.mutation | 3 | false |
| write where root is a local binding | local.mutation | 1 | true |
module top-level binding, content-mutated (no global) | global.mutation | 6 | false |
§Strategy
- Pre-scan the function body for
global/nonlocaldeclarations and local bindings —Assign/AnnAssigntargets (incl. tuple/list/starred destructuring),AugAssignbare-Nametargets,for/async forloop targets,with … as/async with … asnames, andexcept … as/except* … asnames — building theglobals,nonlocals, andlocalssets. (Python scoping: any binding-form in a body makes the name function-local for the whole function.) - Extract parameter names from
unit.params. - Walk the body classifying write targets:
Assign/AnnAssign/AugAssigntargets, and mutating method calls (.append,.update,.add) viaon_callin 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.