Repository navigation
TypedPython gate: rebinding and mixed-element containers - #33
Merged
Merged
Conversation
Step 1 of docs/design/typedpython.md: python -m typedpython check runs Pyrefly with its Any-leak kinds raised to errors, reports user-code expressions of type Any outside cast() (any-flow), and reports the forbidden list as warnings in checked mode and errors in compiled mode. Lives in python-multiplatform-ksp. INTENT gains TypedPython as purpose 4 (maintainer statements quoted); SPEC gains N-6 (partial: not yet run by the build). Refs #16
Pyrefly 1.3.2 reports neither and records no types for assignment targets, but it does record the type of every name load. The gate now writes a probed copy in which each candidate assignment is followed on the same line by a load of its targets (line numbers unchanged), runs Pyrefly on it, and judges the types at the probe positions. The second run happens only when a file assigns a name twice or has a container display. Refs #22
The gate's Pyrefly config lives in a temporary directory, which Pyrefly took as the import root, so relative and absolute self-imports of user packages did not resolve and every value from them failed as any-flow. Each checked file's import root (above its outermost package) now goes on the search path. Red before the fix: 3 failed in test_imports.py. Refs #16
A probed copy written alone into a temporary directory lost its package, so relative imports in it did not resolve, their values were Unknown, and rebinding went unreported in exactly the code that lives in packages. The probe pass now copies each file's package tree with the same layout. Red before the fix: test_rebinding_inside_a_package_with_relative_imports. Refs #22
This was referenced Oct 2, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #22
Stacked on #19. This branch contains #19's commits. Merge #19 first; this PR's own change is the last commit, 38b5118.
Feature added
forbidden/rebinding: flags an unannotated name that is rebound to a value of a different type, including through augmented assignment (total = 0; total += 0.5). Covers function, class and module scope.forbidden/mixed-container: flags a list, set or dict display whose inferred element type is a union ([1, "a"]→list[int | str]).checked, an error undercompiled.x: int | str), an annotated parameter, the same type assigned again, and tuples (they are typed per slot).How it works: Pyrefly records types for name loads, not for assignment targets. So the gate makes a copy of the file and inserts
; xafter each candidate assignment on the same line, which keeps line numbers unchanged. It runs Pyrefly a second time on that copy and reads the types at the inserted positions. That second run happens only for files that assign a name twice or contain a container display.Test added
test_rebinding.py, 14 tests:NotImplementedError: rebinding.probe. The 7 that expect nothing passed trivially, as expected.Documentation corrected
SPEC N-6 now lists the two rules and what they don't cover. Design §6.1 records the method and its cost.
Known cost / gaps
pyrefly checkon the synthetic module (232 ms → 3.6 s, load 41). The synthetictotal += ...triggers the probe pass. Reducing this is TypedPython gate: cut the type-report overhead #21.fortargets and comprehension variables are not probed yet.