Repository navigation
fix False negative: Pyrefly does not emit an unpacking error in for k, v in dict #3352 - #3353
asukaminato0721 wants to merge 2 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
Fixes a false-negative where tuple-unpacking in for loop targets did not report an unpacking error when the iterated element type was string-like (e.g., dict key iteration yielding str), by adding a string-like guard to unpack-length checking and updating/adding regression tests.
Changes:
- Add
is_string_likehelper and emitbad-unpackingwhen unpack-length checking is applied to string-like types. - Update existing string-literal unpacking tests to assert the expected error.
- Add a new regression test covering
for k, v in {"x": 1}andfor a, b in list[str].
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| pyrefly/lib/alt/solve.rs | Add string-like detection and produce BadUnpacking in BindingExpect::UnpackedLength for string-like types. |
| pyrefly/lib/test/assign.rs | Update existing unpack-string tests and add for-loop unpacking regression coverage. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
the added errors for apprise look fishy, both of them are typed as |
|
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
Looks like the problem with tuple handling. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
5729f58 to
62700e8
Compare
Merging this PR will not alter performance
Comparing Footnotes
|
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
stroxler
left a comment
There was a problem hiding this comment.
Thanks! I think this has a number of improvements it needs before we can merge:
Parenthesized generic arguments change meaning
Python treats dict[(str, int)] as dict[str, int]. The new helper instead constructs one tuple-type argument.
Confirmed on the PR head:
dict[(str, int)]errors: “Expected 2 type arguments fordict, got 1.”- For
class Box[T],Box[(int,)]becomesBox[tuple[int]]instead ofBox[int].
Fix: Remove the tuple reinterpretation and preserve Ast::unpack_slice semantics. The new fixture should use list[tuple[str, str]]; list[(str, str)] supplies two arguments to list, not one tuple type.
Star-only string unpacking is rejected despite always being valid
def f(s: str) -> None:
*chars, = sThe PR reports “Cannot unpack str into 0+ values.” This assignment succeeds for every string length, including zero. Both new rejection branches ignore the SizeExpectation::Ge(0) case; LiteralString has the same problem.
Fix: At minimum, exempt Ge(0) and retain ordinary iteration.
Coverage gap
Union members bypass the new string rejection: unpacking elements of list[str | tuple[int, int]] produces no diagnostic. If the broader string-unpacking policy is retained, apply it consistently across branches.
This comment has been minimized.
This comment has been minimized.
|
Diff from mypy_primer, showing the effect of this PR on open source code: ============================================================
SUMMARY
============================================================
Total: +15 new errors, -2 fixed errors
By preset: +15/-0 (default), +15/-0 (strict)
Projects with changes (10):
apprise: +4 -0
setuptools: +1 -0
streamlit: +1 -0
cloud-init: +4 -0
aiohttp: +1 -0
pywin32: +1 -0
werkzeug: +1 -1
spack: +1 -0
pylint: +1 -0
porcupine: +0 -1
============================================================
FULL DIFF DETAILS
------------------------------------------------------------
apprise (https://github.com/caronc/apprise)
+ ERROR apprise/plugins/blink1.py:328:9-16: Cannot unpack str into 3 values [bad-unpacking]
+ ERROR apprise/plugins/xmpp/adapter.py:254:25-38: Cannot unpack str into 2 values [bad-unpacking]
+ ERROR apprise/plugins/xmpp/adapter.py:964:17-30: Cannot unpack str into 2 values [bad-unpacking]
+ ERROR apprise/plugins/xmpp/base.py:374:17-28: Cannot unpack str into 2 values [bad-unpacking]
setuptools (https://github.com/pypa/setuptools)
+ ERROR setuptools/tests/test_build_ext.py:387:11-27: Cannot unpack str into 2 values [bad-unpacking]
streamlit (https://github.com/streamlit/streamlit)
+ ERROR lib/streamlit/runtime/state/query_params.py:917:13-23: Cannot unpack str into 2 values [bad-unpacking]
cloud-init (https://github.com/canonical/cloud-init)
+ ERROR tests/unittests/cmd/devel/test_make_mime.py:40:5-17: Cannot unpack str into 1 value [bad-unpacking]
+ ERROR tests/unittests/test_net.py:2128:17-37: Cannot unpack str into 2 values [bad-unpacking]
+ ERROR tests/unittests/test_net.py:2804:17-37: Cannot unpack str into 2 values [bad-unpacking]
+ ERROR tests/unittests/test_net.py:3053:17-37: Cannot unpack str into 2 values [bad-unpacking]
aiohttp (https://github.com/aio-libs/aiohttp)
+ ERROR aiohttp/cookiejar.py:492:13-25: Cannot unpack str into 2 values [bad-unpacking]
pywin32 (https://github.com/mhammond/pywin32)
+ ERROR win32/Demos/getfilever.py:28:5-19: Cannot unpack str into 2 values [bad-unpacking]
werkzeug (https://github.com/pallets/werkzeug)
- ERROR src/werkzeug/datastructures/headers.py:504:78-104: Unused `# type: ignore` comment [unused-type-ignore]
+ ERROR src/werkzeug/middleware/shared_data.py:115:13-23: Cannot unpack str into 2 values [bad-unpacking]
spack (https://github.com/spack/spack)
+ ERROR lib/spack/spack/spec.py:591:13-47: Cannot unpack str into 3 values [bad-unpacking]
pylint (https://github.com/pycqa/pylint)
+ ERROR pylint/checkers/variables.py:341:9-34: Cannot unpack str into 2 values [bad-unpacking]
porcupine (https://github.com/Akuli/porcupine)
- ERROR porcupine/plugins/directory_tree.py:410:64-78: Unused `# type: ignore` comment [unused-type-ignore] |
Summary
Fixes #3352
unpack-length checking rejects string-like unpack sources (str, string literals, LiteralString) with bad-unpacking, which catches for k, v in {"x": 1} because dict iteration yields keys.
Test Plan
update && add test