mirror of
https://github.com/microsoft/pyright.git
synced 2024-09-11 16:06:39 +03:00
Added support for type constraints of the form "X == None" and "X != None".
This commit is contained in:
parent
f30af50b0e
commit
1bb66de420
@ -1572,11 +1572,14 @@ export class Binder extends ParseTreeWalker {
|
||||
}
|
||||
|
||||
case ParseNodeType.BinaryOperation: {
|
||||
if (expression.operator === OperatorType.Is ||
|
||||
expression.operator === OperatorType.IsNot) {
|
||||
const isOrIsNotOperator = expression.operator === OperatorType.Is ||
|
||||
expression.operator === OperatorType.IsNot;
|
||||
const equalsOrNotEqualsOperator = expression.operator === OperatorType.Equals ||
|
||||
expression.operator === OperatorType.NotEquals;
|
||||
|
||||
// Look for "X is None" or "X is not None". These are commonly-used
|
||||
// patterns used in control flow.
|
||||
if (isOrIsNotOperator || equalsOrNotEqualsOperator) {
|
||||
// Look for "X is None", "X is not None", "X == None", "X != None".
|
||||
// These are commonly-used patterns used in control flow.
|
||||
if (expression.rightExpression.nodeType === ParseNodeType.Constant &&
|
||||
expression.rightExpression.constType === KeywordType.None) {
|
||||
|
||||
@ -1584,7 +1587,8 @@ export class Binder extends ParseTreeWalker {
|
||||
}
|
||||
|
||||
// Look for "type(X) is Y" or "type(X) is not Y".
|
||||
if (expression.leftExpression.nodeType === ParseNodeType.Call &&
|
||||
if (isOrIsNotOperator &&
|
||||
expression.leftExpression.nodeType === ParseNodeType.Call &&
|
||||
expression.leftExpression.leftExpression.nodeType === ParseNodeType.Name &&
|
||||
expression.leftExpression.leftExpression.value === 'type' &&
|
||||
expression.leftExpression.arguments.length === 1 &&
|
||||
|
@ -7255,13 +7255,19 @@ export function createTypeEvaluator(importLookup: ImportLookup): TypeEvaluator {
|
||||
const isPositiveTest = !!(flowNode.flags & FlowFlags.TrueCondition);
|
||||
|
||||
if (testExpression.nodeType === ParseNodeType.BinaryOperation) {
|
||||
if (testExpression.operator === OperatorType.Is || testExpression.operator === OperatorType.IsNot) {
|
||||
const isOrIsNotOperator = testExpression.operator === OperatorType.Is ||
|
||||
testExpression.operator === OperatorType.IsNot;
|
||||
const equalsOrNotEqualsOperator = testExpression.operator === OperatorType.Equals ||
|
||||
testExpression.operator === OperatorType.NotEquals;
|
||||
|
||||
if (isOrIsNotOperator || equalsOrNotEqualsOperator) {
|
||||
// Invert the "isPositiveTest" value if this is an "is not" operation.
|
||||
const adjIsPositiveTest = testExpression.operator === OperatorType.Is ?
|
||||
const adjIsPositiveTest = (testExpression.operator === OperatorType.Is ||
|
||||
testExpression.operator === OperatorType.Equals) ?
|
||||
isPositiveTest : !isPositiveTest;
|
||||
|
||||
// Look for "X is None" or "X is not None". These are commonly-used
|
||||
// patterns used in control flow.
|
||||
// Look for "X is None", "X is not None", "X == None", and "X != None".
|
||||
// These are commonly-used patterns used in control flow.
|
||||
if (testExpression.rightExpression.nodeType === ParseNodeType.Constant &&
|
||||
testExpression.rightExpression.constType === KeywordType.None) {
|
||||
|
||||
@ -7296,7 +7302,7 @@ export function createTypeEvaluator(importLookup: ImportLookup): TypeEvaluator {
|
||||
}
|
||||
|
||||
// Look for "type(X) is Y" or "type(X) is not Y".
|
||||
if (testExpression.leftExpression.nodeType === ParseNodeType.Call) {
|
||||
if (isOrIsNotOperator && testExpression.leftExpression.nodeType === ParseNodeType.Call) {
|
||||
const callType = getTypeOfExpression(testExpression.leftExpression.leftExpression).type;
|
||||
if (callType.category === TypeCategory.Class &&
|
||||
ClassType.isBuiltIn(callType, 'type') &&
|
||||
|
@ -136,6 +136,12 @@ test('TypeConstraint6', () => {
|
||||
validateResults(analysisResults, 1);
|
||||
});
|
||||
|
||||
test('TypeConstraint7', () => {
|
||||
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['typeConstraint7.py']);
|
||||
|
||||
validateResults(analysisResults, 0);
|
||||
});
|
||||
|
||||
test('CircularBaseClass', () => {
|
||||
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['circularBaseClass.py']);
|
||||
|
||||
|
25
server/src/tests/samples/typeConstraint7.py
Normal file
25
server/src/tests/samples/typeConstraint7.py
Normal file
@ -0,0 +1,25 @@
|
||||
# This sample tests the type analyzer's handling of "X is None", "X is not None",
|
||||
# "X == None" and "X != None" conditions.
|
||||
|
||||
# pyright: strict
|
||||
|
||||
from typing import Optional
|
||||
|
||||
def func1(x: Optional[int]):
|
||||
if x is not None:
|
||||
x.bit_length()
|
||||
|
||||
if x != None:
|
||||
x.bit_length()
|
||||
|
||||
if x is None:
|
||||
pass
|
||||
else:
|
||||
x.bit_length()
|
||||
|
||||
if x == None:
|
||||
pass
|
||||
else:
|
||||
x.bit_length()
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user