Added check for a class-scoped generic type alias that uses a class-scoped TypeVar. This is now flagged as an error.

This commit is contained in:
Eric Traut 2021-11-05 19:22:12 -07:00
parent 2044381032
commit 6c9d680b3f
5 changed files with 26 additions and 3 deletions

View File

@ -11801,12 +11801,23 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
}
const fileInfo = AnalyzerNodeInfo.getFileInfo(name);
const typeAliasScopeId = getScopeIdForNode(name);
const boundTypeVars = typeParameters.filter(typeVar => typeVar.scopeId !== typeAliasScopeId);
if (boundTypeVars.length > 0) {
addError(
Localizer.Diagnostic.genericTypeAliasBoundTypeVar().format({
names: boundTypeVars.map(t => `${t.details.name}`).join(', ')
}),
errorNode
);
}
return TypeBase.cloneForTypeAlias(
type,
name.value,
`${fileInfo.moduleName}.${name.value}`,
getScopeIdForNode(name),
typeAliasScopeId,
typeParameters.length > 0 ? typeParameters : undefined
);
}

View File

@ -392,6 +392,8 @@ export namespace Localizer {
export const genericClassAssigned = () => getRawString('Diagnostic.genericClassAssigned');
export const genericClassDeleted = () => getRawString('Diagnostic.genericClassDeleted');
export const genericNotAllowed = () => getRawString('Diagnostic.genericNotAllowed');
export const genericTypeAliasBoundTypeVar = () =>
new ParameterizedString<{ names: string }>(getRawString('Diagnostic.genericTypeAliasBoundTypeVar'));
export const genericTypeArgMissing = () => getRawString('Diagnostic.genericTypeArgMissing');
export const genericTypeArgTypeVar = () => getRawString('Diagnostic.genericTypeArgTypeVar');
export const genericTypeArgUnique = () => getRawString('Diagnostic.genericTypeArgUnique');

View File

@ -157,6 +157,7 @@
"genericClassAssigned": "Generic class type cannot be assigned",
"genericClassDeleted": "Generic class type cannot be deleted",
"genericNotAllowed": "\"Generic\" is not valid in this context",
"genericTypeAliasBoundTypeVar": "Generic type alias within class cannot use bound type variables {names}",
"genericTypeArgMissing": "\"Generic\" requires at least one type argument",
"genericTypeArgTypeVar": "Type argument for \"Generic\" must be a type variable",
"genericTypeArgUnique": "Type arguments for \"Generic\" must be unique",

View File

@ -2,7 +2,7 @@
# TypeVars.
from datetime import datetime
from typing import IO, List, Type, TypeVar, Union
from typing import IO, Dict, Generic, List, Type, TypeVar, Union
_T1 = TypeVar("_T1")
_T2 = TypeVar("_T2")
@ -39,3 +39,12 @@ v2: FooIsh[Bar] = Bar()
# This should generate an error.
v3: FooIsh[Type[Bar]] = 42
MyTypeAlias = Dict[_T1, _T2]
class MyClass1(Generic[_T1, _T2]):
# This should generate an error because S and T are bound
# type variables.
MyTypeAlias = Dict[_T1, _T2]

View File

@ -309,7 +309,7 @@ test('TypeAlias4', () => {
test('TypeAlias5', () => {
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['typeAlias5.py']);
TestUtils.validateResults(analysisResults, 2);
TestUtils.validateResults(analysisResults, 3);
});
test('TypeAlias6', () => {