mirror of
https://github.com/microsoft/pyright.git
synced 2024-09-11 07:55:56 +03:00
Extended type narrowing for type guards of the form x[I] is B
and x[I] is not B
where x
is a tuple and B
is an enum literal.
This commit is contained in:
parent
f1db88481f
commit
08085479ef
@ -68,7 +68,7 @@ In addition to assignment-based type narrowing, Pyright supports the following t
|
|||||||
* `x.y == L` and `x.y != L` (where L is a literal expression and x is a type that is distinguished by a field or property with a literal type)
|
* `x.y == L` and `x.y != L` (where L is a literal expression and x is a type that is distinguished by a field or property with a literal type)
|
||||||
* `x[K] == V`, `x[K] != V`, `x[K] is V`, and `x[K] is not V` (where K and V are literal expressions and x is a type that is distinguished by a TypedDict field with a literal type)
|
* `x[K] == V`, `x[K] != V`, `x[K] is V`, and `x[K] is not V` (where K and V are literal expressions and x is a type that is distinguished by a TypedDict field with a literal type)
|
||||||
* `x[I] == V` and `x[I] != V` (where I and V are literal expressions and x is a known-length tuple that is distinguished by the index indicated by I)
|
* `x[I] == V` and `x[I] != V` (where I and V are literal expressions and x is a known-length tuple that is distinguished by the index indicated by I)
|
||||||
* `x[I] is B` and `x[I] is not B` (where I is a literal expression, B is a `bool` literal, and x is a known-length tuple that is distinguished by the index indicated by I)
|
* `x[I] is B` and `x[I] is not B` (where I is a literal expression, B is a `bool` or enum literal, and x is a known-length tuple that is distinguished by the index indicated by I)
|
||||||
* `x[I] is None` and `x[I] is not None` (where I is a literal expression and x is a known-length tuple that is distinguished by the index indicated by I)
|
* `x[I] is None` and `x[I] is not None` (where I is a literal expression and x is a known-length tuple that is distinguished by the index indicated by I)
|
||||||
* `len(x) == L` and `len(x) != L` (where x is tuple and L is a literal integer)
|
* `len(x) == L` and `len(x) != L` (where x is tuple and L is a literal integer)
|
||||||
* `x in y` or `x not in y` (where y is instance of list, set, frozenset, deque, tuple, dict, defaultdict, or OrderedDict)
|
* `x in y` or `x not in y` (where y is instance of list, set, frozenset, deque, tuple, dict, defaultdict, or OrderedDict)
|
||||||
|
@ -29,6 +29,7 @@ import { getScopeForNode } from './scopeUtils';
|
|||||||
import { Symbol, SymbolFlags } from './symbol';
|
import { Symbol, SymbolFlags } from './symbol';
|
||||||
import { getTypedDictMembersForClass } from './typedDicts';
|
import { getTypedDictMembersForClass } from './typedDicts';
|
||||||
import { EvaluatorFlags, TypeEvaluator } from './typeEvaluatorTypes';
|
import { EvaluatorFlags, TypeEvaluator } from './typeEvaluatorTypes';
|
||||||
|
import { EnumLiteral } from './types';
|
||||||
import {
|
import {
|
||||||
ClassType,
|
ClassType,
|
||||||
ClassTypeFlags,
|
ClassTypeFlags,
|
||||||
@ -281,23 +282,29 @@ export function getTypeNarrowingCallback(
|
|||||||
const rightTypeResult = evaluator.getTypeOfExpression(testExpression.rightExpression);
|
const rightTypeResult = evaluator.getTypeOfExpression(testExpression.rightExpression);
|
||||||
const rightType = rightTypeResult.type;
|
const rightType = rightTypeResult.type;
|
||||||
|
|
||||||
if (
|
if (isClassInstance(rightType) && rightType.literalValue !== undefined) {
|
||||||
isClassInstance(rightType) &&
|
let canNarrow = false;
|
||||||
ClassType.isBuiltIn(rightType, 'bool') &&
|
// Narrowing can be applied only for bool or enum literals.
|
||||||
rightType.literalValue !== undefined
|
if (ClassType.isBuiltIn(rightType, 'bool')) {
|
||||||
) {
|
canNarrow = true;
|
||||||
return (type: Type) => {
|
} else if (rightType.literalValue instanceof EnumLiteral) {
|
||||||
return {
|
canNarrow = true;
|
||||||
type: narrowTypeForDiscriminatedTupleComparison(
|
}
|
||||||
evaluator,
|
|
||||||
type,
|
if (canNarrow) {
|
||||||
indexType,
|
return (type: Type) => {
|
||||||
rightType,
|
return {
|
||||||
adjIsPositiveTest
|
type: narrowTypeForDiscriminatedTupleComparison(
|
||||||
),
|
evaluator,
|
||||||
isIncomplete: !!rightTypeResult.isIncomplete,
|
type,
|
||||||
|
indexType,
|
||||||
|
rightType,
|
||||||
|
adjIsPositiveTest
|
||||||
|
),
|
||||||
|
isIncomplete: !!rightTypeResult.isIncomplete,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
# This sample tests the type narrowing for known-length tuples
|
# This sample tests the type narrowing for known-length tuples
|
||||||
# that have an entry with a declared literal type.
|
# that have an entry with a declared literal type.
|
||||||
|
|
||||||
|
from enum import Enum
|
||||||
from typing import Literal
|
from typing import Literal
|
||||||
|
|
||||||
MsgA = tuple[Literal[1], str]
|
MsgA = tuple[Literal[1], str]
|
||||||
@ -41,3 +42,28 @@ def func4(m: MsgCOrD):
|
|||||||
reveal_type(m, expected_text="tuple[Literal[False], float]")
|
reveal_type(m, expected_text="tuple[Literal[False], float]")
|
||||||
else:
|
else:
|
||||||
reveal_type(m, expected_text="tuple[Literal[True], str]")
|
reveal_type(m, expected_text="tuple[Literal[True], str]")
|
||||||
|
|
||||||
|
|
||||||
|
class MyEnum(Enum):
|
||||||
|
A = 0
|
||||||
|
B = 1
|
||||||
|
|
||||||
|
|
||||||
|
MsgE = tuple[Literal[MyEnum.A], str]
|
||||||
|
MsgF = tuple[Literal[MyEnum.B], float]
|
||||||
|
|
||||||
|
MsgEOrF = MsgE | MsgF
|
||||||
|
|
||||||
|
|
||||||
|
def func5(m: MsgEOrF):
|
||||||
|
if m[0] is MyEnum.A:
|
||||||
|
reveal_type(m, expected_text="tuple[Literal[MyEnum.A], str]")
|
||||||
|
else:
|
||||||
|
reveal_type(m, expected_text="tuple[Literal[MyEnum.B], float]")
|
||||||
|
|
||||||
|
|
||||||
|
def func6(m: MsgEOrF):
|
||||||
|
if m[0] is not MyEnum.A:
|
||||||
|
reveal_type(m, expected_text="tuple[Literal[MyEnum.B], float]")
|
||||||
|
else:
|
||||||
|
reveal_type(m, expected_text="tuple[Literal[MyEnum.A], str]")
|
||||||
|
Loading…
Reference in New Issue
Block a user