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. (#5509)

Co-authored-by: Eric Traut <[email protected]>
  • Loading branch information
erictraut and msfterictraut authored Jul 15, 2023
1 parent 01f40f0 commit 92f4e6b
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 2 deletions.
17 changes: 16 additions & 1 deletion packages/pyright-internal/src/analyzer/typeGuards.ts
Original file line number Diff line number Diff line change
Expand Up @@ -997,7 +997,9 @@ function narrowTypeForIsNone(evaluator: TypeEvaluator, type: Type, isPositiveTes
return transformPossibleRecursiveTypeAlias(subtype);
});

return evaluator.mapSubtypesExpandTypeVars(
let resultIncludesNoneSubtype = false;

const result = evaluator.mapSubtypesExpandTypeVars(
expandedType,
/* conditionFilter */ undefined,
(subtype, unexpandedSubtype) => {
Expand All @@ -1017,19 +1019,32 @@ function narrowTypeForIsNone(evaluator: TypeEvaluator, type: Type, isPositiveTes

// See if it's a match for object.
if (isClassInstance(subtype) && ClassType.isBuiltIn(subtype, 'object')) {
resultIncludesNoneSubtype = true;
return isPositiveTest
? addConditionToType(NoneType.createInstance(), subtype.condition)
: adjustedSubtype;
}

// See if it's a match for None.
if (isNoneInstance(subtype) === isPositiveTest) {
resultIncludesNoneSubtype = true;
return subtype;
}

return undefined;
}
);

// If this is a positive test and the result is a union that includes None,
// we can eliminate all the non-None subtypes include Any or Unknown. If some
// of the subtypes are None types with conditions, retain those.
if (isPositiveTest && resultIncludesNoneSubtype) {
return mapSubtypes(result, (subtype) => {
return isNoneInstance(subtype) ? subtype : undefined;
});
}

return result;
}

// Handle type narrowing for expressions of the form "x is ..." and "x is not ...".
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 92f4e6b

Please sign in to comment.