Added logic to ensure that a TypeVar or ParameterSpecification is assigned to a variable of the same name used within the constructor call.

This commit is contained in:
Eric Traut 2020-05-21 00:52:22 -07:00
parent 191486b3fe
commit 57ab85ef0c
5 changed files with 50 additions and 3 deletions

View File

@ -2248,6 +2248,27 @@ export function createTypeEvaluator(importLookup: ImportLookup, printTypeFlags:
}
function assignTypeToExpression(target: ExpressionNode, type: Type, srcExpr?: ExpressionNode) {
// Is the source expression a TypeVar() call?
if (type.category === TypeCategory.TypeVar) {
if (srcExpr && srcExpr.nodeType === ParseNodeType.Call) {
const callType = getTypeOfExpression(srcExpr.leftExpression).type;
if (
callType.category === TypeCategory.Class &&
(ClassType.isBuiltIn(callType, 'TypeVar') ||
ClassType.isBuiltIn(callType, 'ParameterSpecification'))
) {
if (target.nodeType !== ParseNodeType.Name || target.value !== type.name) {
addError(
`${
type.isParameterSpec ? 'ParameterSpecification' : 'TypeVar'
} must be assigned to a variable named "${type.name}"`,
target
);
}
}
}
}
switch (target.nodeType) {
case ParseNodeType.Name: {
const name = target;

View File

@ -1519,3 +1519,9 @@ test('ClassVar2', () => {
validateResults(analysisResults, 1);
});
test('TypeVar1', () => {
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['typeVar1.py']);
validateResults(analysisResults, 2);
});

View File

@ -8,8 +8,8 @@
from typing import Generic, TypeVar
_A = TypeVar('A')
_B = TypeVar('B')
_A = TypeVar('_A')
_B = TypeVar('_B')
class Foo(Generic[_A, _B]):
def __init__(self, a: _A, b: _B = 'hello'):

View File

@ -3,7 +3,7 @@
from typing import Optional, TypeVar
_T = TypeVar("T")
_T = TypeVar("_T")
def foo1(v: Optional[_T]) -> _T:

View File

@ -0,0 +1,20 @@
# This sample tests that the type checker enforces that the
# assigned name of a TypeVar matches the name provided in
# the TypeVar itself.
from typing import Any, TypeVar
T1 = TypeVar('T1')
# This should generate an error because the TypeVar name
# does not match the name of the variable it is assigned to.
T2 = TypeVar('T3')
T4: Any = TypeVar('T4')
my_dict = {}
# This should generate an error because TypeVars cannot be
# assigned to an index expression.
my_dict['var'] = TypeVar('T5')