resulting `ItemsView` isn't narrowed after `isinstance(..., Mapping)` check (and other oddities)
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 15.6k
- Forks
- 1.8k
- Avg merge
- 12h 13m
- Merged PRs (30d)
- 52
Description
### Summary
Code sample in [pyright playground](https://pyright-play.net/?code=GYJw9gtgBAxmA28CmMAuBLMA7AzldEADmCKlAMJgCuWqSIAUKJLAsmprgHQCGARjHxESZAJJ0IOAGrokAdwA0UcfX7IlAWR6FC6LAHMm4aKgCeug0OKkoAZSo6ROUbSUAVc0ik8QSmDxxUJRAkADckHngAfTNCJAYGNygAXigPOO8QAAoAIjccgEoEgBMkYFYaVBiACyQavX0cLIYoVqgAKhxqEBgkHAAuKC0dBoBtNyV7R1JnWgBdKAAfZToQNSRR1AdkccmHa1RZ1Dm5hRa2qhw6gGskUxwovUCI4qiwYEeJB%2BASKIhtAZQPhgBApKAAMUiVzOBSgAFoAHwUai0ejjOb9c6tGCDSiVNFuBapPGo7JFNpQH4gKBdKg9JD4LA07q9AZYin4croHBPVA8LC9LK0%2BmabQWfQFTEc6WcqCXG53B68l5vD7oL5RKl-AFSmV6qlQaioOAQBl6Zl03q6vU2iq0MHC3qjI0mpBzdm26UhcKRGKeLIuyBIWFQADENOq1HgxSBDImQKoZG5aQAAnBKjU6qhqg08MstoQdm40yiqtmszmDDg9tNDi5jh7PRTvRForEkFl07QQ%2BGcJGqNHY3Z9k560o%2BIn8HgpgcjksoABVLDXLBgORYRtN7HOxOuhYAalSelQndL5M9SHgV2tW4NgdNflLjIt9K46qQkiyks3W5bvvbAa7kGPYRlGMZ8HG46TsmxZdmWtT1FW84FkWJYZuWiGNDWs71u6W4yn%2Bbb%2BnBIF9mBQ4zqOrgJkm04jjM9bzkuK5rhu%2BHSjAO7GkGB5HrQp6VOe0qXteP4UneQEPnaSZMo6SA3k2hF%2BnEgHcaaQm-mErbKR2JFiTKnH3m6UCHoyJ56c2SBbCATIwCUZTSZmmEPHIJDXD4KLFM0FKdCyfSDMM4q7MOtZHAsywqGsfA7ChGzxpRDHzKc7LylEtz3I8uB0DwrzvJ8H7fL8-yEICwKgqkkJXkgMLwkiJKrOiCltDiyL4iA6JgvV9Bfj%2BBpyc%2Bclsk26BcjyWX8oKcmiiMBjfuxYYvr0b5fF%2BUByOq1RQEgAAehboDA6qwAEZAwHSfRQOWUCEOA0UflBSZkMASAifgMDXKY%2BnSv1qT%2BIEuQqJIMjyMFCV1vMORKHJy0FV%2BIGrgAjjwgwAAoADIAOoAEwAJwAAwAIyfZSJCGpJ1XSQNflNbaSkAUZGmKVp-7EWeRMUoZZO8WZAndj%2BITWbZCTZrmbSpKM7IAN744M%2BNKJjgyYwAvmcFJZFkstQJjBRKFkmNKPjBTaww7oBFcNjec1pZOcLVZZO0NuNBpyQ-VbGEO009uVlhcpXGliqZc8OWqvlkiakVALJG4IBUMG7LO45btey5bkeTQXme7mTvEqW3VS4MADMcsF4rRQFEAA)
```python
def count_the_things(
*sources: Mapping[T, SupportsInt] | Iterable[tuple[T, SupportsInt]],
use_keys_instead_of_items_for_maps: bool = False,
) -> Counter[T]:
c: Counter[T] = Counter()
for source in sources:
if isinstance(source, Mapping):
if use_keys_instead_of_items_for_maps:
for outcome in source:
count = source[outcome]
reveal_type(outcome) # should be T, but is T@count_the_things | tuple[T@count_the_things, SupportsInt]
reveal_type(count) # should be SupportsInt, but is SupportsInt | Unknown
c[outcome] += int(count)
else:
for outcome, count in source.items():
reveal_type(outcome) # should be T, but is T@count_the_things | tuple[T@count_the_things, SupportsInt]
reveal_type(count) # should be SupportsInt, but is SupportsInt | Unknown
c[outcome] += int(count)
else:
for outcome, count in source:
reveal_type(outcome)
reveal_type(count)
c[outcome] += int(count)
return c
```
To be fair, pyrefly and ty both choke on this, so I probably screwed something up, but I'm pretty sure these should be narrower than they are. mypy passes (possibly related due to fixing python/mypy#11685).
### Related
* facebook/pyrefly#3106
* astral-sh/ty#3249
### Version
pyright 1.1.408
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Reproduce the narrowing behavior in the linked Pyright playground using pyright 1.1.408, focusing on the isinstance(source, Mapping) branches and their reveal_type results. Compare the inferred types with the stated expectations and verify that the Mapping paths narrow outcome to T and count to SupportsInt without regressing the iterable path.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- devtools
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 65/100