PY-76838 Conformance test failure: aliases_variance.py. Approved in IJ-MR-194934

GitOrigin-RevId: 3dad863825f88471262f20a4d1d37b181602a1d5
This commit is contained in:
Marcus Mews
2026-03-23 18:36:54 +00:00
committed by intellij-monorepo-bot
parent 82f2505a29
commit d7cce9ec1f
4 changed files with 44 additions and 12 deletions
@@ -97,7 +97,11 @@ object PyExpectedVarianceJudgment {
}
private fun fromTypeDeclarationStatement(element: PyTypeDeclarationStatement, parent: PsiElement, context: TypeEvalContext): Variance? {
val parentClass = parent.parent as? PyClass ?: return null
val parentClass = parent.parent
if (parentClass !is PyClass) {
// assume that we are in a type alias: `My_Class_Int = My_Class[int]`
return BIVARIANT
}
val targetExpr = element.target as? PyTargetExpression ?: return null
if (attributeDoesNotAffectVarianceInference(targetExpr)) return null
if (isEffectivelyReadOnly(targetExpr, parentClass, context)) return COVARIANT
@@ -110,7 +114,7 @@ object PyExpectedVarianceJudgment {
context: TypeEvalContext,
): Variance? {
val qualifier = subscriptionExpr.qualifier as? PyReferenceExpression ?: return null
var qualifierType = context.getType(qualifier)
var qualifierType = PyTypingTypeProvider.getType(qualifier, context)?.get()
if (qualifierType is PyClassType && qualifierType !is PyCollectionType) {
// convert raw types to generic types
qualifierType = PyTypeChecker.findGenericDefinitionType(qualifierType.pyClass, context) ?: qualifierType
@@ -129,7 +133,11 @@ object PyExpectedVarianceJudgment {
private fun getTypeParameterVarianceAtIndex(qualifierType: PyClassType, index: Int, context: TypeEvalContext): Variance? {
if (qualifierType is PyCollectionType) {
val typeParamType = qualifierType.elementTypes.getOrNull(index) as? PyTypeVarType ?: return null
// check definition type since generic type aliases are parameterized, i.e.: `A_Alias_1 = ClassA[T_co]` will be ClassA[Any]
val definitionType = PyTypeChecker.findGenericDefinitionType(qualifierType.pyClass, context) ?: qualifierType
val typeParamType = definitionType.elementTypes.getOrNull(index) as? PyTypeVarType
?: qualifierType.elementTypes.getOrNull(index) as? PyTypeVarType
?: return null
return getInferredVariance(typeParamType, context)
}
return null
-1
View File
@@ -2,7 +2,6 @@ aliases_explicit.py
aliases_implicit.py
aliases_recursive.py
aliases_typealiastype.py
aliases_variance.py
annotations_typeexpr.py
callables_annotation.py
callables_kwargs.py
@@ -353,20 +353,32 @@ internal class PyExpectedVarianceJudgmentTest : PyTestCase() {
}
}
// Expect null to avoid variance compatibility inspection check
fun `test Type alias for generic class`() {
doTest("T2]", null, """
fun `test Type alias use for generic class invariant`() {
doTest("T2]", Variance.INVARIANT, """
from typing import TypeVar, Generic
T1 = TypeVar("T1", covariant=True)
class Box(Generic[T1]):
pass
Box_TA = Box[T1]
T1 = TypeVar("T1")
class Box(Generic[T1]): ...
Box_TA: TypeAlias = Box[T1]
T2 = TypeVar("T2", covariant=True)
my_box: Box_TA[T2]
""")
}
fun `test Type alias use for generic class covariant`() {
doTest("T_co] #", Variance.COVARIANT, """
from typing import Generic, TypeVar, TypeAlias
T_co = TypeVar("T_co", covariant=True)
class ClassA(Generic[T_co]): ...
T = TypeVar("T")
A_Alias_1: TypeAlias = ClassA[T]
obj: A_Alias_1[T_co] #
""")
}
// Expect null to avoid variance compatibility inspection check
fun `test Generic class dunder init special case`() {
// actually bivariant
doTest("T):", null, """
@@ -190,4 +190,17 @@ internal class PyVarianceTest : PyTestCase() {
t: ReadOnly[out_T] # expect no error here
""")
}
fun `test Type alias for generic class covariant`() {
doTestByText("""
from typing import Generic, TypeVar, TypeAlias
T = TypeVar("T")
class ClassA(Generic[T]): ...
T_co = TypeVar("T_co", covariant=True)
A_Alias_1: TypeAlias = ClassA[T_co]
class ClassA_2(A_Alias_1[<warning descr="A covariant type variable cannot be used in this invariant position">T_co</warning>]): ...
""")
}
}