mirror of
https://github.com/microsoft/pyright.git
synced 2024-09-11 07:55:56 +03:00
Revert "Add support for type narrowing of NamedTuple fields with "is None" (#3271)"
This reverts commit e296cd58ee
.
This commit is contained in:
parent
e296cd58ee
commit
d1e5c924bd
@ -171,7 +171,6 @@ In addition to assignment-based type narrowing, Pyright supports the following t
|
|||||||
* `type(x) is T` and `type(x) is not T`
|
* `type(x) is T` and `type(x) is not T`
|
||||||
* `x is E` and `x is not E` (where E is a literal enum or bool)
|
* `x is E` and `x is not E` (where E is a literal enum or bool)
|
||||||
* `x == L` and `x != L` (where L is a literal expression)
|
* `x == L` and `x != L` (where L is a literal expression)
|
||||||
* `x.y is None` and `x.y is not None` (where x is a type that is distinguished by a field with a None)
|
|
||||||
* `x.y is E` and `x.y is not E` (where E is a literal enum or bool and x is a type that is distinguished by a field with a literal type)
|
* `x.y is E` and `x.y is not E` (where E is a literal enum or bool and x is a type that is distinguished by a field 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 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 with a literal type)
|
||||||
* `x[K] == V` and `x[K] != 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` and `x[K] != V` (where K and V are literal expressions and x is a type that is distinguished by a TypedDict field with a literal type)
|
||||||
|
@ -65,7 +65,6 @@ import {
|
|||||||
convertToInstance,
|
convertToInstance,
|
||||||
convertToInstantiable,
|
convertToInstantiable,
|
||||||
doForEachSubtype,
|
doForEachSubtype,
|
||||||
getSpecializedTupleType,
|
|
||||||
getTypeCondition,
|
getTypeCondition,
|
||||||
getTypeVarScopeId,
|
getTypeVarScopeId,
|
||||||
isLiteralType,
|
isLiteralType,
|
||||||
@ -356,25 +355,6 @@ export function getTypeNarrowingCallback(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look for X.Y is None or X.Y is not None
|
|
||||||
// These are commonly-used patterns used in control flow.
|
|
||||||
if (
|
|
||||||
testExpression.leftExpression.nodeType === ParseNodeType.MemberAccess &&
|
|
||||||
ParseTreeUtils.isMatchingExpression(reference, testExpression.leftExpression.leftExpression) &&
|
|
||||||
testExpression.rightExpression.nodeType === ParseNodeType.Constant &&
|
|
||||||
testExpression.rightExpression.constType === KeywordType.None
|
|
||||||
) {
|
|
||||||
const memberName = testExpression.leftExpression.memberName;
|
|
||||||
return (type: Type) => {
|
|
||||||
return narrowTypeForDiscriminatedFieldNoneComparison(
|
|
||||||
evaluator,
|
|
||||||
type,
|
|
||||||
memberName.value,
|
|
||||||
adjIsPositiveTest
|
|
||||||
);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (testExpression.operator === OperatorType.In) {
|
if (testExpression.operator === OperatorType.In) {
|
||||||
@ -727,20 +707,24 @@ function narrowTypeForTruthiness(evaluator: TypeEvaluator, type: Type, isPositiv
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handle type narrowing for expressions of the form "a[I] is None" and "a[I] is not None" where
|
// Handle type narrowing for expressions of the form "a[I] is None" and "a[I] is not None" where
|
||||||
// I is an integer and a is a union of Tuples and NamedTuples with known lengths and entry types.
|
// I is an integer and a is a union of Tuples with known lengths and entry types.
|
||||||
function narrowTupleTypeForIsNone(evaluator: TypeEvaluator, type: Type, isPositiveTest: boolean, indexValue: number) {
|
function narrowTupleTypeForIsNone(evaluator: TypeEvaluator, type: Type, isPositiveTest: boolean, indexValue: number) {
|
||||||
return evaluator.mapSubtypesExpandTypeVars(type, /* conditionFilter */ undefined, (subtype) => {
|
return evaluator.mapSubtypesExpandTypeVars(type, /* conditionFilter */ undefined, (subtype) => {
|
||||||
const tupleType = getSpecializedTupleType(subtype);
|
if (
|
||||||
if (!tupleType || isUnboundedTupleClass(tupleType) || !tupleType.tupleTypeArguments) {
|
!isClassInstance(subtype) ||
|
||||||
|
!isTupleClass(subtype) ||
|
||||||
|
isUnboundedTupleClass(subtype) ||
|
||||||
|
!subtype.tupleTypeArguments
|
||||||
|
) {
|
||||||
return subtype;
|
return subtype;
|
||||||
}
|
}
|
||||||
|
|
||||||
const tupleLength = tupleType.tupleTypeArguments.length;
|
const tupleLength = subtype.tupleTypeArguments.length;
|
||||||
if (indexValue < 0 || indexValue >= tupleLength) {
|
if (indexValue < 0 || indexValue >= tupleLength) {
|
||||||
return subtype;
|
return subtype;
|
||||||
}
|
}
|
||||||
|
|
||||||
const typeOfEntry = evaluator.makeTopLevelTypeVarsConcrete(tupleType.tupleTypeArguments[indexValue].type);
|
const typeOfEntry = evaluator.makeTopLevelTypeVarsConcrete(subtype.tupleTypeArguments[indexValue].type);
|
||||||
|
|
||||||
if (isPositiveTest) {
|
if (isPositiveTest) {
|
||||||
if (!evaluator.canAssignType(typeOfEntry, NoneType.createInstance())) {
|
if (!evaluator.canAssignType(typeOfEntry, NoneType.createInstance())) {
|
||||||
@ -1475,41 +1459,6 @@ function narrowTypeForDiscriminatedFieldComparison(
|
|||||||
return narrowedType;
|
return narrowedType;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attempts to narrow a type based on a comparison (equal or not equal)
|
|
||||||
// between a discriminating field that has a declared None type to a
|
|
||||||
// None.
|
|
||||||
function narrowTypeForDiscriminatedFieldNoneComparison(
|
|
||||||
evaluator: TypeEvaluator,
|
|
||||||
referenceType: Type,
|
|
||||||
memberName: string,
|
|
||||||
isPositiveTest: boolean
|
|
||||||
): Type {
|
|
||||||
return mapSubtypes(referenceType, (subtype) => {
|
|
||||||
let memberInfo: ClassMember | undefined;
|
|
||||||
if (isClassInstance(subtype)) {
|
|
||||||
memberInfo = lookUpObjectMember(subtype, memberName);
|
|
||||||
} else if (isInstantiableClass(subtype)) {
|
|
||||||
memberInfo = lookUpClassMember(subtype, memberName);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (memberInfo && memberInfo.isTypeDeclared) {
|
|
||||||
const memberType = evaluator.getTypeOfMember(memberInfo);
|
|
||||||
|
|
||||||
if (isPositiveTest) {
|
|
||||||
if (!evaluator.canAssignType(memberType, NoneType.createInstance())) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (isNoneInstance(memberType)) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return subtype;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attempts to narrow a type based on a "type(x) is y" or "type(x) is not y" check.
|
// Attempts to narrow a type based on a "type(x) is y" or "type(x) is not y" check.
|
||||||
function narrowTypeForTypeIs(type: Type, classType: ClassType, isPositiveTest: boolean) {
|
function narrowTypeForTypeIs(type: Type, classType: ClassType, isPositiveTest: boolean) {
|
||||||
return mapSubtypes(type, (subtype) => {
|
return mapSubtypes(type, (subtype) => {
|
||||||
|
@ -1,35 +0,0 @@
|
|||||||
# This sample tests the type narrowing case for unions of NamedTuples
|
|
||||||
# where one or more of the entries is tested against type None by attribute.
|
|
||||||
|
|
||||||
from typing import NamedTuple, Union
|
|
||||||
|
|
||||||
IntFirst = NamedTuple("IntFirst", [
|
|
||||||
("first", int),
|
|
||||||
("second", None),
|
|
||||||
])
|
|
||||||
|
|
||||||
StrSecond = NamedTuple("StrSecond", [
|
|
||||||
("first", None),
|
|
||||||
("second", str),
|
|
||||||
])
|
|
||||||
|
|
||||||
def func1(a: Union[IntFirst, StrSecond]) -> IntFirst:
|
|
||||||
if a.second is None:
|
|
||||||
reveal_type(a, expected_text="IntFirst")
|
|
||||||
return a
|
|
||||||
else:
|
|
||||||
reveal_type(a, expected_text="StrSecond")
|
|
||||||
raise ValueError()
|
|
||||||
|
|
||||||
|
|
||||||
UnionFirst = NamedTuple("UnionFirst", [
|
|
||||||
("first", Union[None, int]),
|
|
||||||
("second", None),
|
|
||||||
])
|
|
||||||
|
|
||||||
def func2(a: Union[UnionFirst, StrSecond]):
|
|
||||||
if a.first is None:
|
|
||||||
reveal_type(a, expected_text="UnionFirst | StrSecond")
|
|
||||||
else:
|
|
||||||
reveal_type(a, expected_text="UnionFirst")
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
|||||||
# This sample tests the type narrowing case for unions of NamedTuples
|
|
||||||
# where one or more of the entries is tested against type None by index.
|
|
||||||
|
|
||||||
from typing import NamedTuple, Union
|
|
||||||
|
|
||||||
IntFirst = NamedTuple("IntFirst", [
|
|
||||||
("first", int),
|
|
||||||
("second", None),
|
|
||||||
])
|
|
||||||
|
|
||||||
StrSecond = NamedTuple("StrSecond", [
|
|
||||||
("first", None),
|
|
||||||
("second", str),
|
|
||||||
])
|
|
||||||
|
|
||||||
def func1(a: Union[IntFirst, StrSecond]) -> IntFirst:
|
|
||||||
if a[1] is None:
|
|
||||||
reveal_type(a, expected_text="IntFirst")
|
|
||||||
return a
|
|
||||||
else:
|
|
||||||
reveal_type(a, expected_text="StrSecond")
|
|
||||||
raise ValueError()
|
|
||||||
|
|
||||||
|
|
||||||
UnionFirst = NamedTuple("UnionFirst", [
|
|
||||||
("first", Union[None, int]),
|
|
||||||
("second", None),
|
|
||||||
])
|
|
||||||
|
|
||||||
def func2(a: Union[UnionFirst, StrSecond]):
|
|
||||||
if a[0] is None:
|
|
||||||
reveal_type(a, expected_text="UnionFirst | StrSecond")
|
|
||||||
else:
|
|
||||||
reveal_type(a, expected_text="UnionFirst")
|
|
||||||
|
|
@ -302,18 +302,6 @@ test('TypeNarrowingIsNoneTuple1', () => {
|
|||||||
TestUtils.validateResults(analysisResults, 0);
|
TestUtils.validateResults(analysisResults, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('TypeNarrowingIsNoneNamedTuple1', () => {
|
|
||||||
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['typeNarrowingIsNoneNamedTuple1.py']);
|
|
||||||
|
|
||||||
TestUtils.validateResults(analysisResults, 0);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('TypeNarrowingIsNoneNamedTuple2', () => {
|
|
||||||
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['typeNarrowingIsNoneNamedTuple2.py']);
|
|
||||||
|
|
||||||
TestUtils.validateResults(analysisResults, 0);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('TypeNarrowingLiteral1', () => {
|
test('TypeNarrowingLiteral1', () => {
|
||||||
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['typeNarrowingLiteral1.py']);
|
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['typeNarrowingLiteral1.py']);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user