@Override
  @Nullable
  public PyType getType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key) {
    final PsiElement parent = getParentByStub();
    if (parent instanceof PyParameterList) {
      PyFunction func = getContainingFunction((PyParameterList)parent);
      if (func != null) {
        for (PyTypeProvider provider : PyTypeProvider.EP_NAME.getExtensionList()) {
          final Ref<PyType> resultRef = provider.getParameterType(this, func, context);
          if (resultRef != null) {
            return resultRef.get();
          }
        }
        if (isSelf()) {
          // must be 'self' or 'cls'
          final PyClass containingClass = func.getContainingClass();
          if (containingClass != null) {
            final boolean isDefinition = PyUtil.isNewMethod(func) || func.getModifier() == PyAstFunction.Modifier.CLASSMETHOD;

            final PyCollectionType genericType = PyTypeChecker.findGenericDefinitionType(containingClass, context);
            if (genericType != null) {
              return isDefinition ? genericType.toClass() : genericType;
            }

            return new PyClassTypeImpl(containingClass, isDefinition);
          }
        }
        if (isKeywordContainer()) {
          return PyTypeUtil.toKeywordContainerType(this, null);
        }
        if (isPositionalContainer()) {
          return PyTypeUtil.toPositionalContainerType(this, null);
        }
        if (context.maySwitchToAST(this)) {
          final PyExpression defaultValue = getDefaultValue();
          if (defaultValue != null) {
            final PyType type = context.getType(defaultValue);
            if (type != null && !(type instanceof PyNoneType)) {
              if (type instanceof PyTupleType) {
                return PyUnionType.createWeakType(type);
              }
              return type;
            }
          }
        }
        // Guess the type from file-local calls
        if (context.allowCallContext(this)) {
          final List<PyType> types = new ArrayList<>();
          final PyResolveContext resolveContext = PyResolveContext.defaultContext(context);
          final PyCallableParameter parameter = PyCallableParameterImpl.psi(this);

          processLocalCalls(
            func, call -> {
              StreamEx
                .of(call.multiMapArguments(resolveContext))
                .flatCollection(mapping -> mapping.getMappedParameters().entrySet())
                .filter(entry -> parameter.equals(entry.getValue()))
                .map(Map.Entry::getKey)
                .nonNull()
                .map(context::getType)
                .nonNull()
                .forEach(types::add);
              return true;
            }
          );

          if (!types.isEmpty()) {
            return PyUnionType.createWeakType(PyUnionType.union(types));
          }
        }
        if (context.maySwitchToAST(this)) {
          final PyType typeFromUsages = getTypeFromUsages(context);
          if (typeFromUsages != null) {
            return typeFromUsages;
          }
        }
      }
    }
    return null;
  }
@Override
  @Nullable
  public PyType getType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key)