Skip to content

[ty] Track literal iterable emptiness for reachability#25222

Merged
charliermarsh merged 7 commits into
mainfrom
charlie/non-empty-literal
Jun 25, 2026
Merged

[ty] Track literal iterable emptiness for reachability#25222
charliermarsh merged 7 commits into
mainfrom
charlie/non-empty-literal

Conversation

@charliermarsh

@charliermarsh charliermarsh commented May 18, 2026

Copy link
Copy Markdown
Member

Summary

This extends the static reachability analysis for synchronous for loops from #25220 to tuple, list, set, dictionary, string, and bytes literals whose emptiness is known syntactically. We record their static truthiness: a non-empty literal proves that the body executes at least once, while an empty literal marks the body unreachable and prevents its definitions from flowing past the loop.

for item in [1]:
    pass

reveal_type(item)  # Literal[1]

value = 1
for _ in []:
    value = "unreachable"

reveal_type(value)  # Literal[1]

Starred elements and dictionary unpacking remain ambiguous when they are the only elements, while an explicit element still proves non-emptiness. Other iterables continue on the existing ambiguous path. Synchronous literals used in async for do not use this shortcut because they do not satisfy async iteration.

@astral-sh-bot astral-sh-bot Bot added the ty Multi-file analysis & type inference label May 18, 2026
@astral-sh-bot

astral-sh-bot Bot commented May 18, 2026

Copy link
Copy Markdown

Typing conformance results

No changes detected ✅

Current numbers
The percentage of diagnostics emitted that were expected errors held steady at 94.47%. The percentage of expected errors that received a diagnostic held steady at 89.19%. The number of fully passing files held steady at 95/134.

@astral-sh-bot

astral-sh-bot Bot commented May 18, 2026

Copy link
Copy Markdown

Memory usage report

Summary

Project Old New Diff Outcome
prefect 448.12MB 448.27MB +0.03% (154.61kB)
trio 70.26MB 70.29MB +0.05% (35.18kB)
flake8 28.94MB 28.95MB +0.02% (5.91kB)
sphinx 166.58MB 166.58MB -0.00% (1.49kB) ⬇️

Significant changes

Click to expand detailed breakdown

prefect

Name Old New Diff Outcome
infer_expression_types_impl 37.77MB 37.83MB +0.15% (56.50kB)
infer_definition_types 49.92MB 49.96MB +0.07% (36.88kB)
infer_scope_types_impl 30.11MB 30.14MB +0.10% (30.23kB)
all_narrowing_constraints_for_expression 5.19MB 5.21MB +0.51% (27.00kB)
semantic_index 113.89MB 113.89MB +0.00% (1.09kB)
analyze_non_terminal_call::interned_arguments 1.80MB 1.80MB +0.05% (936.00B)
infer_unpack_types 631.55kB 632.34kB +0.13% (816.00B)
analyze_non_terminal_call 1.77MB 1.77MB +0.04% (736.00B)
Type<'db>::apply_specialization_inner_::interned_arguments 2.95MB 2.95MB +0.01% (160.00B)
UnionType 1.07MB 1.07MB +0.01% (112.00B)
Type<'db>::apply_specialization_inner_ 2.03MB 2.03MB +0.00% (96.00B)
loop_header_reachability 251.37kB 251.45kB +0.03% (80.00B)
function_known_decorators 3.04MB 3.04MB +0.00% (32.00B)
infer_statement_types_impl 812.33kB 812.34kB +0.00% (16.00B)

trio

Name Old New Diff Outcome
infer_expression_types_impl 4.37MB 4.39MB +0.38% (16.81kB)
analyze_non_terminal_call 376.73kB 382.63kB +1.57% (5.90kB)
semantic_index 17.69MB 17.69MB +0.03% (4.84kB)
all_narrowing_constraints_for_expression 457.70kB 461.26kB +0.78% (3.55kB)
infer_definition_types 3.96MB 3.97MB +0.04% (1.73kB)
CallableType 665.85kB 666.44kB +0.09% (608.00B)
analyze_non_terminal_call::interned_arguments 302.20kB 302.77kB +0.19% (576.00B)
infer_scope_types_impl 2.40MB 2.40MB +0.02% (528.00B)
infer_deferred_types 1.20MB 1.20MB +0.04% (480.00B)
FunctionType<'db>::signature_ 626.03kB 625.84kB -0.03% (192.00B)
infer_statement_types_impl 34.34kB 34.47kB +0.36% (128.00B)
member_lookup_with_policy_inner::interned_arguments 765.70kB 765.82kB +0.02% (120.00B)
loop_header_reachability 71.16kB 71.24kB +0.11% (80.00B)
member_lookup_with_policy_inner 1.03MB 1.03MB +0.01% (72.00B)

flake8

Name Old New Diff Outcome
infer_expression_types_impl 642.10kB 645.48kB +0.53% (3.38kB)
all_narrowing_constraints_for_expression 71.97kB 73.80kB +2.55% (1.84kB)
infer_definition_types 1000.73kB 1001.23kB +0.05% (504.00B)
loop_header_reachability 9.14kB 9.28kB +1.54% (144.00B)
analyze_non_terminal_call 28.90kB 28.97kB +0.24% (72.00B)
semantic_index 7.85MB 7.85MB -0.00% (32.00B)
infer_scope_types_impl 512.04kB 512.05kB +0.00% (16.00B)

sphinx

Name Old New Diff Outcome
semantic_index 37.29MB 37.29MB -0.01% (4.07kB) ⬇️
infer_expression_types_impl 14.77MB 14.77MB +0.01% (1.29kB) ⬇️
analyze_non_terminal_call::interned_arguments 611.23kB 611.58kB +0.06% (360.00B) ⬇️
infer_definition_types 13.67MB 13.67MB +0.00% (320.00B) ⬇️
analyze_non_terminal_call 662.77kB 663.08kB +0.05% (312.00B) ⬇️
infer_scope_types_impl 8.10MB 8.10MB +0.00% (232.00B) ⬇️
all_narrowing_constraints_for_expression 1.93MB 1.93MB +0.00% (96.00B) ⬇️

@astral-sh-bot

astral-sh-bot Bot commented May 18, 2026

Copy link
Copy Markdown

ecosystem-analyzer results

Lint rule Added Removed Changed
possibly-unresolved-reference 0 124 0
unresolved-attribute 0 3 0
not-iterable 0 2 0
invalid-assignment 0 1 0
possibly-missing-import 0 1 0
Total 0 131 0

Flaky changes detected. This PR summary excludes flaky changes; see the HTML report for details.

Raw diff (131 changes)
black (https://github.com/psf/black)
- src/black/linegen.py:943:12 warning[possibly-unresolved-reference] Name `matching_bracket` used when possibly not defined
- src/black/linegen.py:943:36 warning[possibly-unresolved-reference] Name `tail_leaves` used when possibly not defined
- src/black/linegen.py:947:9 warning[possibly-unresolved-reference] Name `head_leaves` used when possibly not defined
- src/black/linegen.py:947:28 warning[possibly-unresolved-reference] Name `matching_bracket` used when possibly not defined
- src/black/linegen.py:950:9 warning[possibly-unresolved-reference] Name `body_leaves` used when possibly not defined
- src/black/linegen.py:950:28 warning[possibly-unresolved-reference] Name `matching_bracket` used when possibly not defined
- src/black/linegen.py:953:9 warning[possibly-unresolved-reference] Name `tail_leaves` used when possibly not defined
- src/black/linegen.py:953:28 warning[possibly-unresolved-reference] Name `matching_bracket` used when possibly not defined
- src/black/files.py:104:12 warning[possibly-unresolved-reference] Name `directory` used when possibly not defined

cloud-init (https://github.com/canonical/cloud-init)
- tests/unittests/sources/test_init.py:737:26 warning[possibly-unresolved-reference] Name `filename` used when possibly not defined

colour (https://github.com/colour-science/colour)
- colour/io/tm2714.py:1698:44 warning[possibly-unresolved-reference] Name `mapping` used when possibly not defined
- colour/io/tm2714.py:1700:38 warning[possibly-unresolved-reference] Name `mapping` used when possibly not defined
- colour/io/tm2714.py:1702:21 warning[possibly-unresolved-reference] Name `mapping` used when possibly not defined
- colour/io/tm2714.py:1702:45 warning[possibly-unresolved-reference] Name `mapping` used when possibly not defined

core (https://github.com/home-assistant/core)
- homeassistant/components/opower/coordinator.py:299:24 warning[possibly-unresolved-reference] Name `stats` used when possibly not defined
- homeassistant/components/opower/coordinator.py:306:42 warning[possibly-unresolved-reference] Name `stats` used when possibly not defined
- homeassistant/components/opower/coordinator.py:308:21 warning[possibly-unresolved-reference] Name `stats` used when possibly not defined
- homeassistant/components/opower/coordinator.py:310:49 warning[possibly-unresolved-reference] Name `stats` used when possibly not defined
- homeassistant/components/opower/coordinator.py:311:44 warning[possibly-unresolved-reference] Name `stats` used when possibly not defined
- homeassistant/components/opower/coordinator.py:312:35 warning[possibly-unresolved-reference] Name `stats` used when possibly not defined

cryptography (https://github.com/pyca/cryptography)
- tests/hazmat/primitives/test_ssh.py:225:30 warning[possibly-unresolved-reference] Name `private_key` used when possibly not defined
- tests/hazmat/primitives/test_ssh.py:242:26 warning[possibly-unresolved-reference] Name `private_key` used when possibly not defined

ibis (https://github.com/ibis-project/ibis)
- ibis/backends/sql/datatypes.py:80:5 warning[possibly-unresolved-reference] Name `_attr` used when possibly not defined
- ibis/backends/sql/datatypes.py:80:12 warning[possibly-unresolved-reference] Name `_ibis_type` used when possibly not defined
- ibis/backends/sql/datatypes.py:80:24 warning[possibly-unresolved-reference] Name `_sg_type` used when possibly not defined

jax (https://github.com/google/jax)
- jax/_src/internal_test_util/test_harnesses.py:1840:11 warning[possibly-unresolved-reference] Name `shape` used when possibly not defined
- jax/_src/internal_test_util/test_harnesses.py:1841:11 warning[possibly-unresolved-reference] Name `shape` used when possibly not defined
- jax/_src/internal_test_util/test_harnesses.py:1841:31 warning[possibly-unresolved-reference] Name `shape` used when possibly not defined
- jax/_src/internal_test_util/test_harnesses.py:1845:19 warning[possibly-unresolved-reference] Name `shape` used when possibly not defined

mypy (https://github.com/python/mypy)
- mypyc/irbuild/format_str_tokenizer.py:28:55 warning[possibly-missing-import] Member `int_to_str_op` of module `mypyc.primitives.int_ops` may be missing

pandas (https://github.com/pandas-dev/pandas)
- pandas/tests/frame/indexing/test_take.py:48:13 warning[possibly-unresolved-reference] Name `df` used when possibly not defined
- pandas/tests/frame/indexing/test_take.py:50:13 warning[possibly-unresolved-reference] Name `df` used when possibly not defined
- pandas/tests/frame/indexing/test_take.py:52:13 warning[possibly-unresolved-reference] Name `df` used when possibly not defined
- pandas/tests/frame/indexing/test_take.py:54:13 warning[possibly-unresolved-reference] Name `df` used when possibly not defined
- pandas/tests/indexes/timedeltas/test_scalar_compat.py:134:35 warning[possibly-unresolved-reference] Name `r1` used when possibly not defined
- pandas/tests/indexes/timedeltas/test_scalar_compat.py:134:39 warning[possibly-unresolved-reference] Name `s1` used when possibly not defined
- pandas/tests/indexes/timedeltas/test_scalar_compat.py:135:35 warning[possibly-unresolved-reference] Name `r2` used when possibly not defined
- pandas/tests/indexes/timedeltas/test_scalar_compat.py:135:39 warning[possibly-unresolved-reference] Name `s2` used when possibly not defined

pandera (https://github.com/pandera-dev/pandera)
- tests/io/test_pandas_io.py:1545:35 warning[possibly-unresolved-reference] Name `local_dict` used when possibly not defined
- tests/io/test_pandas_io.py:1546:18 warning[possibly-unresolved-reference] Name `local_dict` used when possibly not defined

poetry (https://github.com/python-poetry/poetry)
- src/poetry/repositories/link_sources/html.py:63:77 warning[possibly-unresolved-reference] Name `metadata` used when possibly not defined

psycopg (https://github.com/psycopg/psycopg)
- tools/update_error_prefixes.py:75:22 warning[possibly-unresolved-reference] Name `default_pgroot` used when possibly not defined

pycryptodome (https://github.com/Legrandin/pycryptodome)
- lib/Crypto/SelfTest/Cipher/test_CFB.py:275:44 warning[possibly-unresolved-reference] Name `file_name` used when possibly not defined
- lib/Crypto/SelfTest/Cipher/test_CFB.py:275:55 warning[possibly-unresolved-reference] Name `new_func` used when possibly not defined

pydantic (https://github.com/pydantic/pydantic)
- pydantic/v1/networks.py:350:12 warning[possibly-unresolved-reference] Name `host` used when possibly not defined
- pydantic/v1/networks.py:355:48 warning[possibly-unresolved-reference] Name `host` used when possibly not defined
- pydantic/v1/networks.py:357:50 warning[possibly-unresolved-reference] Name `host` used when possibly not defined
- pydantic/v1/networks.py:364:50 warning[possibly-unresolved-reference] Name `host` used when possibly not defined
- pydantic/v1/networks.py:377:24 warning[possibly-unresolved-reference] Name `host` used when possibly not defined

pywin32 (https://github.com/mhammond/pywin32)
- pythonwin/pywin/idle/PyParse.py:124:5 warning[possibly-unresolved-reference] Name `ch` used when possibly not defined

rotki (https://github.com/rotki/rotki)
- rotkehlchen/tests/api/test_bitcoin_transactions.py:102:12 warning[possibly-unresolved-reference] Name `events` used when possibly not defined
- rotkehlchen/tests/api/test_bitcoin_transactions.py:131:12 warning[possibly-unresolved-reference] Name `events` used when possibly not defined
- rotkehlchen/tests/api/test_bitcoin_transactions.py:149:18 warning[possibly-unresolved-reference] Name `json` used when possibly not defined
- rotkehlchen/tests/api/test_bitcoin_transactions.py:197:12 warning[possibly-unresolved-reference] Name `events` used when possibly not defined
- rotkehlchen/tests/api/test_bitcoin_transactions.py:256:12 warning[possibly-unresolved-reference] Name `events` used when possibly not defined
- rotkehlchen/tests/api/test_solana_transactions.py:288:15 warning[possibly-unresolved-reference] Name `user_address` used when possibly not defined
- rotkehlchen/tests/api/test_solana_transactions.py:298:24 warning[possibly-unresolved-reference] Name `user_address` used when possibly not defined
- rotkehlchen/tests/integration/test_zksynclite.py:84:25 warning[possibly-unresolved-reference] Name `idx` used when possibly not defined
- rotkehlchen/tests/integration/test_zksynclite.py:101:25 warning[possibly-unresolved-reference] Name `idx` used when possibly not defined
- rotkehlchen/tests/unit/test_protocol_balances.py:541:20 warning[possibly-unresolved-reference] Name `tx_decoder` used when possibly not defined
- rotkehlchen/tests/unit/test_protocol_balances.py:990:20 warning[possibly-unresolved-reference] Name `tx_decoder` used when possibly not defined

scikit-learn (https://github.com/scikit-learn/scikit-learn)
- sklearn/covariance/tests/test_graphical_lasso.py:66:40 warning[possibly-unresolved-reference] Name `covs` used when possibly not defined
- sklearn/datasets/_twenty_newsgroups.py:341:9 warning[possibly-unresolved-reference] Name `data` used when possibly not defined
- sklearn/datasets/_twenty_newsgroups.py:342:9 warning[possibly-unresolved-reference] Name `data` used when possibly not defined
- sklearn/datasets/_twenty_newsgroups.py:343:9 warning[possibly-unresolved-reference] Name `data` used when possibly not defined
- sklearn/decomposition/tests/test_factor_analysis.py:75:9 warning[possibly-unresolved-reference] Name `fa` used when possibly not defined
- sklearn/decomposition/tests/test_factor_analysis.py:76:9 warning[possibly-unresolved-reference] Name `fa` used when possibly not defined
- sklearn/decomposition/tests/test_factor_analysis.py:77:15 warning[possibly-unresolved-reference] Name `fa` used when possibly not defined
- sklearn/decomposition/tests/test_factor_analysis.py:78:21 warning[possibly-unresolved-reference] Name `fa` used when possibly not defined
- sklearn/ensemble/tests/test_bagging.py:632:47 error[not-iterable] Object of type `None | BaggingClassifier` may not be iterable
- sklearn/ensemble/tests/test_forest.py:1326:47 error[not-iterable] Object of type `None | Any` may not be iterable
- sklearn/ensemble/tests/test_forest.py:1331:9 error[unresolved-attribute] Attribute `apply` is not defined on `None` in union `None | Any`
- sklearn/feature_extraction/tests/test_text.py:564:31 warning[possibly-unresolved-reference] Name `counts_test` used when possibly not defined
- sklearn/svm/tests/test_svm.py:80:24 warning[possibly-unresolved-reference] Name `clf` used when possibly not defined
- sklearn/svm/tests/test_svm.py:80:46 warning[possibly-unresolved-reference] Name `clf` used when possibly not defined
- sklearn/tests/test_discriminant_analysis.py:400:45 warning[possibly-unresolved-reference] Name `solver` used when possibly not defined

scipy (https://github.com/scipy/scipy)
- scipy/optimize/tests/test__numdiff.py:42:30 warning[possibly-unresolved-reference] Name `A` used when possibly not defined
- scipy/optimize/tests/test__numdiff.py:43:30 warning[possibly-unresolved-reference] Name `A` used when possibly not defined
- scipy/interpolate/tests/test_fitpack2.py:170:13 warning[possibly-unresolved-reference] Name `spl` used when possibly not defined
- scipy/interpolate/tests/test_interpolate.py:1229:62 warning[possibly-unresolved-reference] Name `x` used when possibly not defined
- scipy/io/arff/_arffread.py:449:12 warning[possibly-unresolved-reference] Name `restr` used when possibly not defined
- scipy/io/arff/_arffread.py:452:22 warning[possibly-unresolved-reference] Name `regexp` used when possibly not defined
- scipy/io/arff/_arffread.py:455:20 warning[possibly-unresolved-reference] Name `matches` used when possibly not defined
- scipy/io/arff/_arffread.py:456:13 warning[possibly-unresolved-reference] Name `matches` used when possibly not defined
- scipy/sparse/tests/test_base.py:1531:25 warning[possibly-unresolved-reference] Name `S_casted` used when possibly not defined
- scipy/sparse/tests/test_base.py:1531:59 warning[possibly-unresolved-reference] Name `S_casted` used when possibly not defined
- scipy/sparse/tests/test_base.py:1532:28 warning[possibly-unresolved-reference] Name `S_casted` used when possibly not defined
- scipy/sparse/tests/test_base.py:1533:41 warning[possibly-unresolved-reference] Name `S_casted` used when possibly not defined
- scipy/sparse/tests/test_base.py:1546:20 warning[possibly-unresolved-reference] Name `S_casted` used when possibly not defined
- scipy/sparse/tests/test_base.py:1549:22 warning[possibly-unresolved-reference] Name `S_casted` used when possibly not defined
- scipy/sparse/tests/test_base.py:1552:22 warning[possibly-unresolved-reference] Name `S_casted` used when possibly not defined
- scipy/spatial/transform/tests/test_rigid_transform.py:853:24 warning[possibly-unresolved-reference] Name `n` used when possibly not defined

spack (https://github.com/spack/spack)
- lib/spack/spack/package_prefs.py:149:27 warning[possibly-unresolved-reference] Name `variants` used when possibly not defined
- lib/spack/spack/package_prefs.py:150:33 warning[possibly-unresolved-reference] Name `variants` used when possibly not defined
- lib/spack/spack/package_prefs.py:154:46 warning[possibly-unresolved-reference] Name `variants` used when possibly not defined
- lib/spack/spack/package_prefs.py:225:8 warning[possibly-unresolved-reference] Name `readable` used when possibly not defined
- lib/spack/spack/package_prefs.py:227:8 warning[possibly-unresolved-reference] Name `readable` used when possibly not defined
- lib/spack/spack/package_prefs.py:230:8 warning[possibly-unresolved-reference] Name `writable` used when possibly not defined
- lib/spack/spack/package_prefs.py:231:12 warning[possibly-unresolved-reference] Name `readable` used when possibly not defined
- lib/spack/spack/package_prefs.py:238:8 warning[possibly-unresolved-reference] Name `writable` used when possibly not defined
- lib/spack/spack/package_prefs.py:239:12 warning[possibly-unresolved-reference] Name `readable` used when possibly not defined
- lib/spack/spack/package_prefs.py:261:12 warning[possibly-unresolved-reference] Name `group` used when possibly not defined
- lib/spack/spack/vendor/markupsafe/__init__.py:191:9 warning[possibly-unresolved-reference] Name `method` used when possibly not defined
- lib/spack/spack/vendor/ruamel/yaml/emitter.py:1512:20 warning[possibly-unresolved-reference] Name `pos` used when possibly not defined

spark (https://github.com/apache/spark)
- python/pyspark/ml/tests/connect/test_legacy_mode_evaluation.py:133:13 warning[possibly-unresolved-reference] Name `auprc_evaluator` used when possibly not defined
- python/pyspark/mllib/tests/test_feature.py:153:26 warning[possibly-unresolved-reference] Name `mat` used when possibly not defined
- python/pyspark/pandas/tests/frame/test_reindexing.py:550:42 warning[possibly-unresolved-reference] Name `keep` used when possibly not defined
- python/pyspark/pandas/tests/frame/test_reindexing.py:554:48 warning[possibly-unresolved-reference] Name `keep` used when possibly not defined
- python/pyspark/pandas/tests/frame/test_reindexing.py:551:43 warning[possibly-unresolved-reference] Name `keep` used when possibly not defined
- python/pyspark/pandas/tests/frame/test_reindexing.py:555:49 warning[possibly-unresolved-reference] Name `keep` used when possibly not defined
- python/pyspark/pandas/tests/groupby/test_aggregate.py:109:40 warning[possibly-unresolved-reference] Name `as_index` used when possibly not defined
- python/pyspark/sql/tests/test_functions.py:1586:59 warning[possibly-unresolved-reference] Name `aq` used when possibly not defined

static-frame (https://github.com/static-frame/static-frame)
- static_frame/test/property/test_util.py:259:25 warning[possibly-unresolved-reference] Name `post` used when possibly not defined

sympy (https://github.com/sympy/sympy)
- sympy/combinatorics/tests/test_perm_groups.py:195:5 warning[possibly-unresolved-reference] Name `G` used when possibly not defined
- sympy/combinatorics/tests/test_perm_groups.py:196:32 warning[possibly-unresolved-reference] Name `G` used when possibly not defined
- sympy/combinatorics/tests/test_perm_groups.py:196:35 warning[possibly-unresolved-reference] Name `G` used when possibly not defined
- sympy/concrete/tests/test_sums_products.py:792:12 warning[possibly-unresolved-reference] Name `func` used when possibly not defined
- sympy/concrete/tests/test_sums_products.py:793:12 warning[possibly-unresolved-reference] Name `func` used when possibly not defined
- sympy/concrete/tests/test_sums_products.py:794:12 warning[possibly-unresolved-reference] Name `func` used when possibly not defined
- sympy/concrete/tests/test_sums_products.py:795:12 warning[possibly-unresolved-reference] Name `func` used when possibly not defined
- sympy/series/residues.py:69:17 warning[possibly-unresolved-reference] Name `s` used when possibly not defined
- sympy/printing/pretty/pretty.py:1498:9 error[invalid-assignment] Object of type `Unknown` is not assignable to attribute `baseline` on type `None | Unknown | prettyForm`
- sympy/printing/pretty/pretty.py:1498:22 error[unresolved-attribute] Attribute `height` is not defined on `None` in union `None | Unknown | prettyForm`
- sympy/printing/pretty/pretty.py:1502:25 error[unresolved-attribute] Attribute `right` is not defined on `None` in union `None | Unknown | prettyForm`
- sympy/utilities/tests/test_iterables.py:416:39 warning[possibly-unresolved-reference] Name `nul` used when possibly not defined
- sympy/utilities/tests/test_iterables.py:418:39 warning[possibly-unresolved-reference] Name `nul` used when possibly not defined
- sympy/utilities/tests/test_iterables.py:419:39 warning[possibly-unresolved-reference] Name `nul` used when possibly not defined

tornado (https://github.com/tornadoweb/tornado)
- tornado/test/httpclient_test.py:682:34 warning[possibly-unresolved-reference] Name `resp` used when possibly not defined

vision (https://github.com/pytorch/vision)
- test/test_transforms.py:1949:26 warning[possibly-unresolved-reference] Name `mean` used when possibly not defined
- test/test_transforms.py:1949:32 warning[possibly-unresolved-reference] Name `std` used when possibly not defined
- torchvision/models/feature_extraction.py:601:87 warning[possibly-unresolved-reference] Name `name` used when possibly not defined

Full report with detailed diff (timing results)

@charliermarsh charliermarsh force-pushed the charlie/range branch 10 times, most recently from 9d3860e to 667a3fb Compare May 19, 2026 12:20
@charliermarsh charliermarsh force-pushed the charlie/range branch 3 times, most recently from 5b9c09e to 53006b1 Compare May 30, 2026 13:49
@charliermarsh charliermarsh force-pushed the charlie/range branch 2 times, most recently from 2ae6e9f to 1b3dc8e Compare June 12, 2026 17:10
@charliermarsh charliermarsh force-pushed the charlie/range branch 2 times, most recently from add7d4b to 96af416 Compare June 25, 2026 01:39
@charliermarsh charliermarsh force-pushed the charlie/non-empty-literal branch from 1c906d8 to 61346dc Compare June 25, 2026 01:52
@charliermarsh charliermarsh changed the title [ty] View ecosystem report for non-empty literals [ty] Treat non-empty literal iterables as non-empty for reachability Jun 25, 2026
Base automatically changed from charlie/range to main June 25, 2026 01:56
@charliermarsh charliermarsh force-pushed the charlie/non-empty-literal branch from 61346dc to 7d2f48c Compare June 25, 2026 01:58
@charliermarsh charliermarsh changed the title [ty] Treat non-empty literal iterables as non-empty for reachability [ty] Track literal iterable emptiness for reachability Jun 25, 2026
@charliermarsh charliermarsh requested a review from carljm June 25, 2026 02:09
@charliermarsh charliermarsh marked this pull request as ready for review June 25, 2026 02:09
@charliermarsh charliermarsh requested a review from a team as a code owner June 25, 2026 02:09
@charliermarsh charliermarsh requested a review from a team as a code owner June 25, 2026 02:09
Comment thread crates/ty_python_semantic/resources/mdtest/loops/for.md
Comment thread crates/ty_python_core/src/builder.rs Outdated
{
let after_iter = self.flow_snapshot();
let constraint = self
.record_reachability_constraint(PredicateOrLiteral::Literal(is_non_empty));

@carljm carljm Jun 25, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this PR can be significantly simpler. There's no need to create a node in the reachability TDD for a reachability decision that we can make with full confidence immediately in semantic indexing. For these cases we can instead just merge or not-merge control flow snapshots directly here. I think the pattern here should be: "what is the known emptiness of the iterator? if empty, mark loop body unreachable and restore post-iterator snapshot before visiting else. if non-empty, visit body normally and do not merge zero-iteration path back in. if unknown, then we check for possibly adding a range constraint node, and proceed as main currently does."

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call, thank you!

@charliermarsh charliermarsh force-pushed the charlie/non-empty-literal branch from cbd8135 to 5798505 Compare June 25, 2026 11:11
@charliermarsh charliermarsh requested a review from carljm June 25, 2026 11:12
@charliermarsh charliermarsh force-pushed the charlie/non-empty-literal branch from 5798505 to 4c6cc9b Compare June 25, 2026 11:26

@carljm carljm left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, thanks!


```py
def _(items: list[int], mapping: dict[str, int]):
for item in [*items]:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like we are smart about the fact that [*items, 1] is known non-empty (and similar for e.g. {*mapping, "c": 2}), but this is currently not tested.

@charliermarsh charliermarsh force-pushed the charlie/non-empty-literal branch from 4c6cc9b to b9864b6 Compare June 25, 2026 17:32
@charliermarsh charliermarsh enabled auto-merge (squash) June 25, 2026 17:32
@charliermarsh charliermarsh merged commit 6a2e694 into main Jun 25, 2026
62 checks passed
@charliermarsh charliermarsh deleted the charlie/non-empty-literal branch June 25, 2026 17:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ty Multi-file analysis & type inference

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants