microsoft / microsoft/pyright

Incorrect narrowing applied for `x is type(<final type instance>)` construct

Open
#10,622 0 comments 0 reactions 0 assignees View on GitHub
bug
Dominant language
Python
Stars
15.6k
Forks
1.8k
Avg merge
12h 13m
Merged PRs (30d)
52

Description

**Describe the bug**
pyright support narrowing using constructs of the form `x is `:

```python
def ok1(x: int | type[None]):
if x is NoneType:
reveal_type(x) # Type of "x" is "type[None]"
else:
reveal_type(x) # Type of "x" is "int"
reveal_type(x) # Type of "x" is "type[None] | int"
```

However, things seem to go wrong if `` is replaced with `type(`):
```python
def bad1(x: int | type[None]):
if x is type(None):
reveal_type(x) #
else:
reveal_type(x) # Type of "x" is "int"
reveal_type(x) # Type of "x" is "int"
```

I don't necessarily expect pyright to support the latter case as a narrowing construct, but I would expect it to either narrow differently or not narrow at all.

This seems to apply to any final type, not just `NoneType`.

playground: [link](https://pyright-play.net/?code=GYJw9gtgBALgngBwJYDsDmUkQWEMrCoCGANgFCiSyICmAzptrvgHJgo0AqtZZAAoRSkyAYxJE6DAIIAuKADpFvMgGIoAXk1QwAayJwNm3gBMawbToCMACgAec1PgA%2B1BDQDabDgF0AlDLIoIMxzW0wGLy5aAODYqBAaADcaUgB9eDc7XyC1bjdtcwAiW0LwqEKMj0jvQsDgmhI6Ghi4oITktMqsnKg8mgLykrLCx1rY9pSSdNpuuNzaAeLSpAYK2k92Gm8oF1HlU3NdACY7BxRnVw8pPxagpFCy2TrWic6Z22yoefywIqGV8qVdzXMb1RrNZ5xV5TLofHp9Rb-VZ7cZJSbTTJwuZfXoLX6DZarIHXHaYc61XhqTTqKAAIyIxkM6hMZjpDJs9jJFyB1X8kPuUDCAK6kT5rTaaLemM%2BagAPABXFAJIgiAAWRFpJBoAD5IQ0mrcoZKYe8Zbifn9CeUUcFoRiaLNYt9%2BvilsM9izzPTjCdOY5ScSbvyHsKZlJrL4xeK7bCzQqlSk1RqtbrYvqIeL4sb7bNnYirSNyZCY6bWnnXUjrUWyEA)

**VS Code extension or command-line**
```shell
$ pyright --version
pyright 1.1.402
```

Contributor guide

Open the contributing guide

Research direction

Reproduce the narrowing behavior in the linked pyright playground or with pyright 1.1.402 using the examples. Then locate the narrowing implementation and regression tests; done means `type(None)` no longer makes the `if` branch unreachable or discards the post-conditional union, with the intended behavior covered by a test.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
compilers
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.