Fixed a bug that led to incorrect type evaluation when a constrained TypeVar includes literal types as constraints. This addresses #6917. (#6929)

This commit is contained in:
Eric Traut 2024-01-06 15:19:03 -07:00 committed by GitHub
parent 9b64d81c94
commit 064f02e15e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 37 additions and 1 deletions

View File

@ -12,4 +12,5 @@
"source.organizeImports": "explicit"
},
"typescript.tsdk": "node_modules/typescript/lib",
"python.languageServer": "None",
}

View File

@ -52,6 +52,7 @@ import {
getTypeCondition,
getTypeVarScopeId,
isEffectivelyInstantiable,
isLiteralTypeOrUnion,
isPartlyUnknown,
mapSubtypes,
sortTypes,
@ -652,6 +653,7 @@ function assignTypeToConstrainedTypeVar(
const curWideTypeBound = curEntry?.wideBound;
const curNarrowTypeBound = curEntry?.narrowBound;
let forceRetainLiterals = false;
if (isTypeVar(srcType)) {
if (
@ -785,6 +787,8 @@ function assignTypeToConstrainedTypeVar(
})
);
return false;
} else if (isLiteralTypeOrUnion(constrainedType)) {
forceRetainLiterals = true;
}
if (curNarrowTypeBound && !isAnyOrUnknown(curNarrowTypeBound)) {
@ -829,7 +833,14 @@ function assignTypeToConstrainedTypeVar(
} else {
// Assign the type to the type var.
if (!typeVarContext.isLocked() && isTypeVarInScope) {
updateTypeVarType(evaluator, typeVarContext, destType, constrainedType, curWideTypeBound);
updateTypeVarType(
evaluator,
typeVarContext,
destType,
constrainedType,
curWideTypeBound,
forceRetainLiterals
);
}
}

View File

@ -0,0 +1,18 @@
# This tests the handling of a constrained TypeVar with literal types
# in the constraints.
from typing import TypeVar, Literal, Generic
T = TypeVar("T", Literal[True], Literal[False])
class A(Generic[T]):
def __init__(self, null: T = False) -> None:
pass
A(null=bool()) # Type error
reveal_type(A(null=False), expected_text="A[Literal[False]]")
reveal_type(A(), expected_text="A[Literal[False]]")
reveal_type(A(null=True), expected_text="A[Literal[True]]")

View File

@ -518,6 +518,12 @@ test('ConstrainedTypeVar18', () => {
TestUtils.validateResults(analysisResults, 0);
});
test('ConstrainedTypeVar19', () => {
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['constrainedTypeVar19.py']);
TestUtils.validateResults(analysisResults, 1);
});
test('MissingTypeArg1', () => {
const configOptions = new ConfigOptions(Uri.empty());