From 90473326acf56dc9e215215fa02c5e1abc42d182 Mon Sep 17 00:00:00 2001 From: Daniil Kalinin Date: Mon, 10 Mar 2025 15:33:08 +0100 Subject: [PATCH] PY-76814 Add variance field to `PyTypeVarType` GitOrigin-RevId: 2e7fe0b149a7412c4fdae924a846f200e82786a0 --- .../python/psi/types/PyTypeVarType.java | 6 +++++ .../typing/PyTypingTypeProvider.java | 25 +++++++++++++++++-- .../python/psi/types/PyGenericType.java | 21 +++++++++++----- .../python/psi/types/PyTypeVarTypeImpl.java | 10 +++++--- 4 files changed, 50 insertions(+), 12 deletions(-) diff --git a/python/python-psi-api/src/com/jetbrains/python/psi/types/PyTypeVarType.java b/python/python-psi-api/src/com/jetbrains/python/psi/types/PyTypeVarType.java index ba6d6ad6d7b8..d89c276647ff 100644 --- a/python/python-psi-api/src/com/jetbrains/python/psi/types/PyTypeVarType.java +++ b/python/python-psi-api/src/com/jetbrains/python/psi/types/PyTypeVarType.java @@ -34,4 +34,10 @@ public interface PyTypeVarType extends PyTypeParameterType, PyInstantiableType

{ return new PyParamSpecType(name) @@ -1543,6 +1545,25 @@ public final class PyTypingTypeProvider extends PyTypeProviderWithCustomContext< return null; } + private static @NotNull PyTypeVarType.Variance getTypeVarVarianceFromDeclaration(@NotNull PyCallExpression assignedCall) { + boolean covariant = PyEvaluator.evaluateAsBooleanNoResolve(assignedCall.getKeywordArgument("covariant"), false); + boolean contravariant = PyEvaluator.evaluateAsBooleanNoResolve(assignedCall.getKeywordArgument("contravariant"), false); + boolean inferVariance = PyEvaluator.evaluateAsBooleanNoResolve(assignedCall.getKeywordArgument("infer_variance"), false); + + if (covariant && !contravariant) { + return PyTypeVarType.Variance.COVARIANT; + } + else if (contravariant && !covariant) { + return PyTypeVarType.Variance.CONTRAVARIANT; + } + else if (inferVariance) { + return PyTypeVarType.Variance.INFER_VARIANCE; + } + else { + return PyTypeVarType.Variance.INVARIANT; + } + } + @ApiStatus.Internal public static @Nullable PyAstTypeParameter.Kind getTypeParameterKindFromDeclaration(@NotNull PyCallExpression callExpression, @NotNull TypeEvalContext context) { @@ -1600,7 +1621,7 @@ public final class PyTypingTypeProvider extends PyTypeProviderWithCustomContext< else if (boundExpression != null) { boundType = Ref.deref(getTypePreventingRecursion(boundExpression, context)); } - return new PyTypeVarTypeImpl(name, constraints, boundType, defaultType) + return new PyTypeVarTypeImpl(name, constraints, boundType, defaultType, PyTypeVarType.Variance.INFER_VARIANCE) .withScopeOwner(scopeOwner) .withDeclarationElement(declarationElement); } diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyGenericType.java b/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyGenericType.java index 8078d6c61396..a7a9c5593f86 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyGenericType.java +++ b/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyGenericType.java @@ -27,6 +27,7 @@ public class PyGenericType implements PyTypeVarType { private final @NotNull List<@Nullable PyType> myConstraints; private final @Nullable PyType myBound; private final @Nullable Ref myDefaultType; + private final @NotNull Variance myVariance; private final boolean myIsDefinition; private final @Nullable PyQualifiedNameOwner myDeclarationElement; private final @Nullable PyQualifiedNameOwner myScopeOwner; @@ -34,14 +35,16 @@ public class PyGenericType implements PyTypeVarType { public PyGenericType(@NotNull String name, @NotNull List<@Nullable PyType> constraints, @Nullable PyType bound, - @Nullable Ref defaultType) { - this(name, constraints, bound, defaultType, false, null, null); + @Nullable Ref defaultType, + @NotNull Variance variance) { + this(name, constraints, bound, defaultType, variance, false, null, null); } protected PyGenericType(@NotNull String name, @NotNull List<@Nullable PyType> constraints, @Nullable PyType bound, @Nullable Ref defaultType, + @NotNull Variance variance, boolean isDefinition, @Nullable PyQualifiedNameOwner declarationElement, @Nullable PyQualifiedNameOwner scopeOwner) { @@ -49,6 +52,7 @@ public class PyGenericType implements PyTypeVarType { myConstraints = constraints; myBound = bound; myDefaultType = defaultType; + myVariance = variance; myIsDefinition = isDefinition; myDeclarationElement = declarationElement; myScopeOwner = scopeOwner; @@ -156,6 +160,11 @@ public class PyGenericType implements PyTypeVarType { return myBound; } + @Override + public @NotNull Variance getVariance() { + return myVariance; + } + @Override public @Nullable Ref getDefaultType() { return myDefaultType; @@ -172,7 +181,7 @@ public class PyGenericType implements PyTypeVarType { } public @NotNull PyGenericType withScopeOwner(@Nullable PyQualifiedNameOwner scopeOwner) { - return new PyTypeVarTypeImpl(getName(), getConstraints(), getBound(), getDefaultType(), isDefinition(), getDeclarationElement(), scopeOwner); + return new PyTypeVarTypeImpl(getName(), getConstraints(), getBound(), getDefaultType(), getVariance(), isDefinition(), getDeclarationElement(), scopeOwner); } public @NotNull PyGenericType withTargetExpression(@Nullable PyTargetExpression targetExpression) { @@ -180,16 +189,16 @@ public class PyGenericType implements PyTypeVarType { } public @NotNull PyGenericType withDeclarationElement(@Nullable PyQualifiedNameOwner declarationElement) { - return new PyTypeVarTypeImpl(getName(), getConstraints(), getBound(), getDefaultType(), isDefinition(), declarationElement, getScopeOwner()); + return new PyTypeVarTypeImpl(getName(), getConstraints(), getBound(), getDefaultType(), getVariance(), isDefinition(), declarationElement, getScopeOwner()); } @Override public @NotNull PyGenericType toInstance() { - return myIsDefinition ? new PyTypeVarTypeImpl(myName, myConstraints, myBound, myDefaultType, false, myDeclarationElement, myScopeOwner) : this; + return myIsDefinition ? new PyTypeVarTypeImpl(myName, myConstraints, myBound, myDefaultType, myVariance, false, myDeclarationElement, myScopeOwner) : this; } @Override public @NotNull PyGenericType toClass() { - return myIsDefinition ? this : new PyTypeVarTypeImpl(myName, myConstraints, myBound, myDefaultType, true, myDeclarationElement, myScopeOwner); + return myIsDefinition ? this : new PyTypeVarTypeImpl(myName, myConstraints, myBound, myDefaultType, myVariance, true, myDeclarationElement, myScopeOwner); } } diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyTypeVarTypeImpl.java b/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyTypeVarTypeImpl.java index cdd09fbe1601..68bf05c9cd30 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyTypeVarTypeImpl.java +++ b/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyTypeVarTypeImpl.java @@ -9,24 +9,26 @@ import java.util.List; public final class PyTypeVarTypeImpl extends PyGenericType { public PyTypeVarTypeImpl(@NotNull String name, @Nullable PyType bound) { - this(name, List.of(), bound, null); + this(name, List.of(), bound, null, Variance.INVARIANT); } public PyTypeVarTypeImpl(@NotNull String name, @NotNull List<@Nullable PyType> constraints, @Nullable PyType bound, - @Nullable Ref defaultType) { - super(name, constraints, bound, defaultType); + @Nullable Ref defaultType, + @NotNull Variance variance) { + super(name, constraints, bound, defaultType, variance); } PyTypeVarTypeImpl(@NotNull String name, @NotNull List<@Nullable PyType> constraints, @Nullable PyType bound, @Nullable Ref defaultType, + @NotNull Variance variance, boolean isDefinition, @Nullable PyQualifiedNameOwner declarationElement, @Nullable PyQualifiedNameOwner scopeOwner) { - super(name, constraints, bound, defaultType, isDefinition, declarationElement, scopeOwner); + super(name, constraints, bound, defaultType, variance, isDefinition, declarationElement, scopeOwner); } @Override