• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

source-academy / py-slang / 33766385549
86%

Build:
DEFAULT BRANCH: main
Ran 03 Sep 2026 02:37PM UTC
Jobs 1
Files 139
Run time 1min
Badge
Embed ▾
README BADGES
x

If you need to use a raster PNG badge, change the '.svg' to '.png' in the link

Markdown

Textile

RDoc

HTML

Rst

03 Sep 2026 02:21PM UTC coverage: 85.748% (+0.06%) from 85.684%
33766385549

push

github

web-flow
Stepper: alpha-rename a parameter/local that would capture a substituted value's free variable (#455)

* Stepper: alpha-rename a parameter/local that would capture a substituted value's free variable

substituteOrTag (the substitution stepper's core recursive substitution/tagging
walk) only ever checked whether the *substituted-for* name was shadowed by a
lambda/def's own parameter (or a def's own name/reassigned locals) before
descending — it never checked the opposite direction: whether the
*substituted-in* value's own free variables collided with one of those same
bound names. When they did, the free variable was silently captured by the
unrelated, same-named binding instead of staying correctly shadowed.

Reported repro:

    f = lambda x: y
    y = 1
    g = lambda y: f(y)
    print(g(2))

prints 1 on the home tab (CSE machine) but printed 2 on the stepper tab: g's
own parameter y captured f's free y (the module-level one) once f's
definition was substituted into g's body. The equivalent JS Source program on
the old (non-conductor) stepper renames the capturing parameter first
(js-slang's StepperArrowFunctionExpression.substitute /
StepperBlockStatement.substitute, src/stepper/nodes/...) — this port of the
substitution model never carried that capture-avoidance over.

Fix: a new avoidCapture, run right before substituteOrTag descends into an
ArrowFunctionExpression/FunctionDeclaration's body, alpha-renames any of that
scope's own bound names (parameters, or for a def, any name its body assigns
anywhere — assignedNamesOf, Python's own whole-function-locality rule) that
collide with the incoming value's free names, throughout the node's own
params/body (renameOwnBinding/renameShadowAware) — before the ordinary
substitution proceeds. The rename target is picked via freshName, mirroring
js-slang's own getFreshName suffix scheme (y -> y_1 -> y_2, ...) so a renamed
parameter reads the same way in both steppers. A nested lambda/def that
independently re... (continued)

4889 of 6128 branches covered (79.78%)

Branch coverage included in aggregate %.

61 of 61 new or added lines in 1 file covered. (100.0%)

10916 of 12304 relevant lines covered (88.72%)

162161.78 hits per line

Jobs
ID Job ID Ran Files Coverage
1 33766385549.1 03 Sep 2026 02:37PM UTC 139
85.75
GitHub Action Run
Source Files on build 33766385549
  • Tree
  • List 139
  • Changed 1
  • Source Changed 1
  • Coverage Changed 1
Coverage ∆ File Lines Relevant Covered Missed Hits/Line Branch Hits Branch Misses
  • Back to Repo
  • Github Actions Build #33766385549
  • dcee3002 on github
  • Prev Build on main (#33709168755)
  • Next Build on main (#33767654208)
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc