private static boolean matchesByArgumentTypes(@NotNull PyFunction callable,
                                                @NotNull PyCallSiteExpression callSite,
                                                @NotNull TypeEvalContext context) {
    final PyCallExpression.PyArgumentsMapping fullMapping = mapArguments(callSite, callable, context);
    if (!fullMapping.getUnmappedArguments().isEmpty() || !fullMapping.getUnmappedParameters().isEmpty()) {
      return false;
    }

    // TODO properly handle bidirectional operator methods, such as __eq__ and __neq__. 
    //  Based only on its name, it's impossible to which operand is the receiver and which one is the argument. 
    final PyExpression receiver = callSite.getReceiver(callable);
    final Map<PyExpression, PyCallableParameter> mappedExplicitParameters = fullMapping.getMappedParameters();

    final Map<PyExpression, PyCallableParameter> allMappedParameters = new LinkedHashMap<>();
    final PyCallableParameter firstImplicit = ContainerUtil.getFirstItem(fullMapping.getImplicitParameters());
    if (receiver != null && firstImplicit != null) {
      allMappedParameters.put(receiver, firstImplicit);
    }
    allMappedParameters.putAll(mappedExplicitParameters);

    return PyTypeChecker.unifyGenericCall(receiver, allMappedParameters, context) != null;
  }
private static boolean matchesByArgumentTypes(@NotNull PyFunction callable,
                                                @NotNull PyCallSiteExpression callSite,
                                                @NotNull TypeEvalContext context)