Skip to content

Commit

Permalink
Modified is None type guard logic to eliminate Any or Unknown i…
Browse files Browse the repository at this point in the history
…n the positive narrowing case. This addresses #5508.
  • Loading branch information
msfterictraut committed Jul 15, 2023
1 parent 01f40f0 commit 9fc9311
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 5 deletions.
2 changes: 1 addition & 1 deletion docs/type-concepts-advanced.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ This “narrowing for implied else” technique works for all narrowing expressi

### Narrowing Any

In general, the type `Any` is not narrowed. The only exceptions to this rule are the built-in `isinstance` and `issubclass` type guards, class pattern matching in “match” statements, and user-defined type guards. In all other cases, `Any` is left as is, even for assignments.
In general, the type `Any` is not narrowed. The only exceptions to this rule are the built-in `isinstance`, `issubclass`, and `is None` type guards, class pattern matching in “match” statements, and user-defined type guards. In all other cases, `Any` is left as is, even for assignments.

```python
a: Any = 3
Expand Down
6 changes: 3 additions & 3 deletions packages/pyright-internal/src/analyzer/typeGuards.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1002,9 +1002,9 @@ function narrowTypeForIsNone(evaluator: TypeEvaluator, type: Type, isPositiveTes
/* conditionFilter */ undefined,
(subtype, unexpandedSubtype) => {
if (isAnyOrUnknown(subtype)) {
// We need to assume that "Any" is always both None and not None,
// so it matches regardless of whether the test is positive or negative.
return subtype;
// If it's an Any or Unknown, we can definitively say that it's
// a None based on this type guard.
return isPositiveTest ? NoneType.createInstance() : subtype;
}

// If this is a TypeVar that isn't constrained, use the unexpanded
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

# pyright: strict, reportUnusedVariable=false

from typing import TypeVar
from typing import Any, Literal, Protocol, TypeVar


def func1(x: int | None):
Expand Down Expand Up @@ -54,3 +54,29 @@ def func4(x: _T2) -> _T2:
else:
reveal_type(x, expected_text="_T2@func4")
return x


def func5(x: Any | None):
if x is None:
reveal_type(x, expected_text="None")
else:
reveal_type(x, expected_text="Any")


def func6(x: Any | object | None):
if x is None:
reveal_type(x, expected_text="None")
else:
reveal_type(x, expected_text="Any | object")


class NoneProto(Protocol):
def __bool__(self) -> Literal[False]:
...


def func7(x: NoneProto | None):
if x is None:
reveal_type(x, expected_text="None")
else:
reveal_type(x, expected_text="NoneProto")

0 comments on commit 9fc9311

Please sign in to comment.