From 6e2c7614ca64638f5e6ea49e4667ecfdd882aada Mon Sep 17 00:00:00 2001 From: Daniil Kalinin Date: Wed, 4 Feb 2026 18:01:52 +0100 Subject: [PATCH] PY-79067 Allow creating `PyCallableType` directly with `PyCallableParameterVariadicType` instead of wrapping it in the list of callable parameters This refactoring allows simplifying and unifying logic whilst calculating substitutions for callable types and its matching in `PyTypeChecker` GitOrigin-RevId: e61bd1f6cf19539b0a66ff2e3e47164aec0c0aa1 --- .../python/psi/types/PyCallableType.java | 15 ++ .../typing/PyTypingTypeProvider.java | 12 +- .../python/psi/impl/ParamHelper.java | 14 +- .../python/psi/impl/PyCallExpressionHelper.kt | 2 +- .../python/psi/types/PyCallableTypeImpl.java | 48 ++++-- .../python/psi/types/PyClassTypeImpl.java | 6 + .../psi/types/PyCloningTypeVisitor.java | 13 +- .../python/psi/types/PyFunctionTypeImpl.java | 6 + .../python/psi/types/PyNamedTupleType.java | 6 + .../python/psi/types/PyTypeChecker.java | 140 +++++++----------- .../python/psi/types/PyTypedDictType.kt | 4 + .../python/psi/types/PyTypingNewType.kt | 4 + 12 files changed, 147 insertions(+), 123 deletions(-) diff --git a/python/python-psi-api/src/com/jetbrains/python/psi/types/PyCallableType.java b/python/python-psi-api/src/com/jetbrains/python/psi/types/PyCallableType.java index 8da0158f7468..49d11f986649 100644 --- a/python/python-psi-api/src/com/jetbrains/python/psi/types/PyCallableType.java +++ b/python/python-psi-api/src/com/jetbrains/python/psi/types/PyCallableType.java @@ -47,6 +47,21 @@ public interface PyCallableType extends PyType { return null; } + /** + * Returns the parameters type as a variadic type. + * This method provides a unified way to handle different forms of callable parameters: + * + * @return the parameters type, or null if not applicable + */ + @ApiStatus.Experimental + default @Nullable PyCallableParameterVariadicType getParametersType(@NotNull TypeEvalContext context) { + return null; + } + @Override @Nullable default String getName() { diff --git a/python/python-psi-impl/src/com/jetbrains/python/codeInsight/typing/PyTypingTypeProvider.java b/python/python-psi-impl/src/com/jetbrains/python/codeInsight/typing/PyTypingTypeProvider.java index 8faaa1b2c799..6b7f9235d295 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/codeInsight/typing/PyTypingTypeProvider.java +++ b/python/python-psi-impl/src/com/jetbrains/python/codeInsight/typing/PyTypingTypeProvider.java @@ -1686,15 +1686,11 @@ public final class PyTypingTypeProvider extends PyTypeProviderWithCustomContext< returnType = null; } if (parametersExpr instanceof PyEllipsisLiteralExpression) { - return new PyCallableTypeImpl(null, returnType); + return new PyCallableTypeImpl((PyCallableParameterVariadicType)null, returnType); } PyType parametersType = Ref.deref(getType(parametersExpr, context)); - if (parametersType instanceof PyCallableParameterListType paramList) { - return new PyCallableTypeImpl(paramList.getParameters(), returnType); - } - if (parametersType instanceof PyParamSpecType || parametersType instanceof PyConcatenateType) { - PyCallableParameter paramSpecParam = PyCallableParameterImpl.nonPsi(parametersType); - return new PyCallableTypeImpl(Collections.singletonList(paramSpecParam), returnType); + if (parametersType instanceof PyCallableParameterVariadicType variadicType) { + return new PyCallableTypeImpl(variadicType, returnType); } } } @@ -1702,7 +1698,7 @@ public final class PyTypingTypeProvider extends PyTypeProviderWithCustomContext< } else if (resolved instanceof PyTargetExpression targetExpression) { if (resolvesToQualifiedNames(targetExpression, context.getTypeContext(), CALLABLE, CALLABLE_EXT)) { - return new PyCallableTypeImpl(null, null); + return new PyCallableTypeImpl((PyCallableParameterVariadicType)null, null); } } return null; diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/ParamHelper.java b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/ParamHelper.java index 8e3fad8ddd11..081725f0d016 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/ParamHelper.java +++ b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/ParamHelper.java @@ -187,8 +187,11 @@ public final class ParamHelper { public static boolean isSelfArgsKwargsCallable(@NotNull PyCallableType type, @NotNull TypeEvalContext context) { final List parameters = type.getParameters(context); - return parameters != null - && parameters.size() == 3 && + return parameters != null && isSelfArgsKwargsSignature(parameters); + } + + public static boolean isSelfArgsKwargsSignature(@NotNull List parameters) { + return parameters.size() == 3 && parameters.get(0).isSelf() && parameters.get(1).isPositionalContainer() && parameters.get(2).isKeywordContainer(); @@ -196,8 +199,11 @@ public final class ParamHelper { public static boolean isArgsKwargsCallable(@NotNull PyCallableType type, @NotNull TypeEvalContext context) { final List parameters = type.getParameters(context); - return parameters != null - && parameters.size() == 2 && + return parameters != null && isArgsKwargsSignature(parameters); + } + + public static boolean isArgsKwargsSignature(@NotNull List parameters) { + return parameters.size() == 2 && parameters.get(0).isPositionalContainer() && parameters.get(1).isKeywordContainer(); } diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.kt b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.kt index 35eb097d2a25..fa68b7bfa7b0 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.kt +++ b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.kt @@ -371,7 +371,7 @@ private fun PyCallSiteExpression.toCallableType( } return PyCallableTypeImpl( - callableType.getParameters(context), + callableType.getParametersType(context), clarifiedConstructorCallType ?: callableType.getCallType(context, this), clarifiedResolved, resolvedModifier, diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyCallableTypeImpl.java b/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyCallableTypeImpl.java index 05cd02756e8a..dbe8bb091c2d 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyCallableTypeImpl.java +++ b/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyCallableTypeImpl.java @@ -26,14 +26,30 @@ import java.util.Map; import java.util.Objects; public class PyCallableTypeImpl implements PyCallableType { - private final @Nullable List myParameters; + private final @Nullable PyCallableParameterVariadicType myParametersType; private final @Nullable PyType myReturnType; private final @Nullable PyCallable myCallable; private final @Nullable PyFunction.Modifier myModifier; private final int myImplicitOffset; + public PyCallableTypeImpl(@Nullable PyCallableParameterVariadicType parametersType, @Nullable PyType returnType) { + this(parametersType, returnType, null, null, 0); + } + + public PyCallableTypeImpl(@Nullable PyCallableParameterVariadicType parametersType, + @Nullable PyType returnType, + @Nullable PyCallable callable, + @Nullable PyFunction.Modifier modifier, + int offset) { + myParametersType = parametersType; + myReturnType = returnType; + myCallable = callable; + myModifier = modifier; + myImplicitOffset = offset; + } + public PyCallableTypeImpl(@Nullable List parameters, @Nullable PyType returnType) { - this(parameters, returnType, null, null, 0); + this(parameters != null ? new PyCallableParameterListTypeImpl(parameters) : null, returnType, null, null, 0); } public PyCallableTypeImpl(@Nullable List parameters, @@ -41,11 +57,7 @@ public class PyCallableTypeImpl implements PyCallableType { @Nullable PyCallable callable, @Nullable PyFunction.Modifier modifier, int offset) { - myParameters = parameters; - myReturnType = returnType; - myCallable = callable; - myModifier = modifier; - myImplicitOffset = offset; + this(parameters != null ? new PyCallableParameterListTypeImpl(parameters) : null, returnType, callable, modifier, offset); } @Override @@ -81,7 +93,19 @@ public class PyCallableTypeImpl implements PyCallableType { @Override public @Nullable List getParameters(@NotNull TypeEvalContext context) { - return myParameters; + if (myParametersType instanceof PyCallableParameterListType parameterListType) { + return parameterListType.getParameters(); + } + // For backward compatibility with code that expects a single parameter wrapping ParamSpec/Concatenate + if (myParametersType instanceof PyParamSpecType || myParametersType instanceof PyConcatenateType) { + return Collections.singletonList(PyCallableParameterImpl.nonPsi(myParametersType)); + } + return null; + } + + @Override + public @Nullable PyCallableParameterVariadicType getParametersType(@NotNull TypeEvalContext context) { + return myParametersType; } @Override @@ -138,6 +162,10 @@ public class PyCallableTypeImpl implements PyCallableType { @Override public @NotNull PyCallableType dropSelf(@NotNull TypeEvalContext context) { + if (!(myParametersType instanceof PyCallableParameterListType)) { + return this; + } + final List parameters = getParameters(context); if (parameters != null && myCallable instanceof PyFunction function) { final List functionParameters = function.getParameters(context); @@ -157,7 +185,7 @@ public class PyCallableTypeImpl implements PyCallableType { if (o == null || getClass() != o.getClass()) return false; PyCallableTypeImpl type = (PyCallableTypeImpl)o; return myImplicitOffset == type.myImplicitOffset && - Objects.equals(myParameters, type.myParameters) && + Objects.equals(myParametersType, type.myParametersType) && Objects.equals(myReturnType, type.myReturnType) && Objects.equals(myCallable, type.myCallable) && myModifier == type.myModifier; @@ -165,6 +193,6 @@ public class PyCallableTypeImpl implements PyCallableType { @Override public int hashCode() { - return Objects.hash(myParameters, myReturnType, myCallable, myModifier, myImplicitOffset); + return Objects.hash(myParametersType, myReturnType, myCallable, myModifier, myImplicitOffset); } } diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java b/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java index e45cd86f7e1d..abc6fc0bcb22 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java +++ b/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java @@ -397,6 +397,12 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { .orElse(null); } + @Override + public @Nullable PyCallableParameterVariadicType getParametersType(@NotNull TypeEvalContext context) { + List parameters = getParameters(context); + return parameters != null ? new PyCallableParameterListTypeImpl(parameters) : null; + } + private static boolean isMethodType(@NotNull PyClassType type) { final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(type.getPyClass()); return type.equals(builtinCache.getClassMethodType()) || diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyCloningTypeVisitor.java b/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyCloningTypeVisitor.java index e251febf1c7f..e241cab18cb2 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyCloningTypeVisitor.java +++ b/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyCloningTypeVisitor.java @@ -198,18 +198,9 @@ public abstract class PyCloningTypeVisitor extends PyTypeVisitorExt { @Override public PyType visitPyCallableType(@NotNull PyCallableType callableType) { - List parameters = callableType.getParameters(myTypeEvalContext); + PyCallableParameterVariadicType clonedParametersType = clone(callableType.getParametersType(myTypeEvalContext)); return new PyCallableTypeImpl( - parameters != null ? ContainerUtil.map(parameters, parameter -> - new PyCallableParameterImpl( - parameter.getName(), - Ref.create(clone(parameter.getType(myTypeEvalContext))), - parameter.getDefaultValue(), - parameter.getParameter(), - parameter.isPositionalContainer(), - parameter.isKeywordContainer(), - parameter.getDeclarationElement() - )) : null, + clonedParametersType, clone(callableType.getReturnType(myTypeEvalContext)), callableType.getCallable(), callableType.getModifier(), diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyFunctionTypeImpl.java b/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyFunctionTypeImpl.java index c1834cff0cf6..1f6ad20e4c6a 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyFunctionTypeImpl.java +++ b/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyFunctionTypeImpl.java @@ -73,6 +73,12 @@ public class PyFunctionTypeImpl implements PyFunctionType { return myParameters; } + @Override + public @Nullable PyCallableParameterVariadicType getParametersType(@NotNull TypeEvalContext context) { + List parameters = ContainerUtil.notNullize(getParameters(context)); + return new PyCallableParameterListTypeImpl(parameters); + } + @Override public @Nullable List resolveMember(@NotNull String name, @Nullable PyExpression location, diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyNamedTupleType.java b/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyNamedTupleType.java index b6f33b446f7e..a600155186dd 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyNamedTupleType.java +++ b/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyNamedTupleType.java @@ -177,6 +177,12 @@ public class PyNamedTupleType extends PyTupleType implements PyCallableType { : null; } + @Override + public @Nullable PyCallableParameterVariadicType getParametersType(@NotNull TypeEvalContext context) { + List parameters = getParameters(context); + return parameters != null ? new PyCallableParameterListTypeImpl(parameters) : null; + } + public boolean isTyped() { return myTyped; } diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyTypeChecker.java b/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyTypeChecker.java index cfe4c78c16ed..8882501697cf 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyTypeChecker.java +++ b/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyTypeChecker.java @@ -541,7 +541,7 @@ public final class PyTypeChecker { @NotNull MatchContext context) { if (actual == null) return true; if (!(actual instanceof PyCallableParameterListType actualParameters)) return false; - return matchCallableParameters(expectedParameters.getParameters(), actualParameters.getParameters(), context); + return match(expectedParameters, actualParameters, context); } private static boolean match(@NotNull PyType expected, @NotNull PyUnionType actual, @NotNull MatchContext context) { @@ -872,36 +872,17 @@ public final class PyTypeChecker { return actualAttributes.containsAll(expected.getAttributeNames()); } - private static boolean matchCallableParameters(@NotNull List expectedParameters, - @NotNull List actualParameters, - @NotNull MatchContext matchContext) { + private static boolean match(@NotNull PyCallableParameterListType expectedParametersType, + @NotNull PyCallableParameterListType actualParametersType, + @NotNull MatchContext matchContext) { TypeEvalContext context = matchContext.context; - if (expectedParameters.size() == 1) { - PyType onlyExpectedParamType = expectedParameters.get(0).getType(context); - if (onlyExpectedParamType instanceof PyParamSpecType expectedParamSpecType) { - if (actualParameters.size() == 1) { - PyType actualOnlyParamType = actualParameters.get(0).getType(context); - if (actualOnlyParamType instanceof PyParamSpecType || actualOnlyParamType instanceof PyConcatenateType) { - return match(expectedParamSpecType, actualOnlyParamType, matchContext); - } - } - return match(expectedParamSpecType, new PyCallableParameterListTypeImpl(actualParameters), matchContext); - } - else if (onlyExpectedParamType instanceof PyConcatenateType expectedConcatenateType) { - if (actualParameters.size() == 1) { - PyType actualOnlyParamType = actualParameters.get(0).getType(context); - if (actualOnlyParamType instanceof PyParamSpecType || actualOnlyParamType instanceof PyConcatenateType) { - return match(expectedConcatenateType, actualOnlyParamType, matchContext); - } - } - return match(expectedConcatenateType, new PyCallableParameterListTypeImpl(actualParameters), matchContext); - } - } + List expectedParameters = expectedParametersType.getParameters(); + List actualParameters = actualParametersType.getParameters(); int startIndex = 0; if (!expectedParameters.isEmpty() && !actualParameters.isEmpty()) { - var firstExpectedParam = expectedParameters.get(0); - var firstActualParam = actualParameters.get(0); + var firstExpectedParam = expectedParameters.getFirst(); + var firstActualParam = actualParameters.getFirst(); if (firstExpectedParam.isSelf() && firstActualParam.isSelf()) { if (!match(firstExpectedParam.getType(context), firstActualParam.getType(context), matchContext).orElse(true)) { return false; @@ -945,10 +926,11 @@ public final class PyTypeChecker { } if (expected.isCallable() && actual.isCallable()) { - final List expectedParameters = expected.getParameters(context); - final List actualParameters = actual.getParameters(context); - if (expectedParameters != null && actualParameters != null) { - if (!matchCallableParameters(expectedParameters, actualParameters, matchContext)) { + final PyCallableParameterVariadicType expectedParametersType = expected.getParametersType(context); + final PyCallableParameterVariadicType actualParametersType = actual.getParametersType(context); + + if (expectedParametersType != null && actualParametersType != null) { + if (!match(expectedParametersType, actualParametersType, matchContext).orElse(true)) { return Optional.of(false); } } @@ -1458,71 +1440,51 @@ public final class PyTypeChecker { @Override public PyType visitPyCallableType(@NotNull PyCallableType callableType) { - List parameters = callableType.getParameters(context); - boolean isSelfArgsKwargs = ParamHelper.isSelfArgsKwargsCallable(callableType, context); - boolean isArgsKwargs = ParamHelper.isArgsKwargsCallable(callableType, context); - if (parameters != null && (isSelfArgsKwargs || isArgsKwargs)) { - int argsIndex; - if (isSelfArgsKwargs) { - argsIndex = 1; - } - else { - argsIndex = 0; - } - PyCallableParameter args = parameters.get(argsIndex); - PyType argsType = args.getType(context); - PyCallableParameterVariadicType substituted = substitutions.getParamSpecs().get(argsType); - - if (substituted instanceof PyCallableParameterListType listType) { - List newParameters = listType.getParameters(); - if (isSelfArgsKwargs) { - newParameters = ContainerUtil.prepend(newParameters, parameters.getFirst()); - } - return new PyCallableTypeImpl(newParameters, clone(callableType.getReturnType(context)), callableType.getCallable(), - callableType.getModifier(), callableType.getImplicitOffset()); - } - } - @Nullable PyType parametersSubs; - if (parameters != null) { - PyCallableParameter onlyParam = ContainerUtil.getOnlyItem(parameters); - if (onlyParam != null && onlyParam.getType(context) instanceof PyParamSpecType paramSpecType) { - parametersSubs = clone(paramSpecType); - } - else if (onlyParam != null && onlyParam.getType(context) instanceof PyConcatenateType concatenateType) { - parametersSubs = clone(concatenateType); - } - else { - parametersSubs = new PyCallableParameterListTypeImpl( - StreamEx.of(parameters) - .mapToEntry(param -> param.getType(context)) - .flatMapKeyValue((param, paramType) -> { - PyParameter paramPsi = param.getParameter(); - return StreamEx.of(Collections.singletonList(param.getType(context))) - .flatCollection(t -> flattenUnpackedTuple(clone(t))) - .map(paramSubType -> paramPsi != null ? - PyCallableParameterImpl.psi(paramPsi, paramSubType) : - PyCallableParameterImpl.nonPsi(param.getName(), paramSubType, param.getDefaultValue())); - }) - .toList() - ); - } - } - else { - parametersSubs = null; - } + PyCallableParameterVariadicType substitutedParams = clone(callableType.getParametersType(context)); return new PyCallableTypeImpl( - parametersSubs instanceof PyCallableParameterListType parameterList ? parameterList.getParameters() : - parametersSubs instanceof PyConcatenateType concat ? List.of(PyCallableParameterImpl.nonPsi(concat)) : - parametersSubs instanceof PyParamSpecType paramSpec ? List.of(PyCallableParameterImpl.nonPsi(paramSpec)) : - null, - clone(callableType.getReturnType(context)) - , + substitutedParams, + clone(callableType.getReturnType(context)), callableType.getCallable(), callableType.getModifier(), callableType.getImplicitOffset() ); } + @Override + public PyType visitPyCallableParameterListType(@NotNull PyCallableParameterListType callableParameterListType) { + List parameters = callableParameterListType.getParameters(); + + boolean isSelfArgsKwargs = ParamHelper.isSelfArgsKwargsSignature(parameters); + boolean isArgsKwargs = ParamHelper.isArgsKwargsSignature(parameters); + // substitutes (*args: P.args, **kwargs: P.kwargs) with actual signature + if (isSelfArgsKwargs || isArgsKwargs) { + PyType kwargsType = parameters.getLast().getType(context); + PyCallableParameterVariadicType substituted = substitutions.getParamSpecs().get(kwargsType); + + if (substituted instanceof PyCallableParameterListType listType) { + List newParams = listType.getParameters(); + if (isSelfArgsKwargs) { + newParams = ContainerUtil.prepend(newParams, parameters.getFirst()); + } + return new PyCallableParameterListTypeImpl(newParams); + } + } + + List substitutedParams = StreamEx.of(parameters) + .mapToEntry(param -> param.getType(context)) + .flatMapKeyValue((param, paramType) -> { + PyParameter paramPsi = param.getParameter(); + return StreamEx.of(Collections.singletonList(param.getType(context))) + .flatCollection(t -> flattenUnpackedTuple(clone(t))) + .map(paramSubType -> paramPsi != null ? + PyCallableParameterImpl.psi(paramPsi, paramSubType) : + PyCallableParameterImpl.nonPsi(param.getName(), paramSubType, param.getDefaultValue())); + }) + .toList(); + + return new PyCallableParameterListTypeImpl(substitutedParams); + } + @Override public PyCallableParameterVariadicType visitPyConcatenateType(@NotNull PyConcatenateType concatenateType) { List firstParamTypeSubs = ContainerUtil.flatMap(concatenateType.getFirstTypes(), t -> flattenUnpackedTuple(clone(t))); diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyTypedDictType.kt b/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyTypedDictType.kt index 4bb7dc9d3a9f..b7f357dafa4b 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyTypedDictType.kt +++ b/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyTypedDictType.kt @@ -68,6 +68,10 @@ class PyTypedDictType( else null } + override fun getParametersType(context: TypeEvalContext): PyCallableParameterVariadicType? { + return getParameters(context)?.let { PyCallableParameterListTypeImpl(it) } + } + override fun toString(): String = "PyTypedDictType: $name" override fun equals(other: Any?): Boolean { diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyTypingNewType.kt b/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyTypingNewType.kt index d8d85beda2b0..f1f576fe0903 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyTypingNewType.kt +++ b/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyTypingNewType.kt @@ -47,6 +47,10 @@ class PyTypingNewType( } } + override fun getParametersType(context: TypeEvalContext): PyCallableParameterVariadicType? { + return getParameters(context)?.let { PyCallableParameterListTypeImpl(it) } + } + override fun getSuperClassTypes(context: TypeEvalContext): List = listOf(classType) override fun resolveMember(