public static @Nullable PyType getCallType(@NotNull PyBinaryExpression binaryExpression,
                                             @NotNull TypeEvalContext context,
                                             @NotNull TypeEvalContext.Key key) {
    final PyResolveContext resolveContext = PyResolveContext.defaultContext(context);
    List<@NotNull PyCallableType> callableTypes = multiResolveCallee((PyReferenceOwner)binaryExpression, resolveContext);
    // TODO split normal and reflected operator methods and process them separately
    //  e.g. if there is matching __add__ of the left operand, don't consider signatures of __radd__ of the right operand, etc.  
    List<PyCallableType> matchingCallableTypes = ContainerUtil.filter(
      callableTypes, 
      callable -> callable.getCallable() instanceof PyFunction function && matchesByArgumentTypes(function, binaryExpression, context)
    );
    return matchingCallableTypes.isEmpty() ? getCallType(callableTypes, binaryExpression, context) 
                                           : getCallType(matchingCallableTypes, binaryExpression, context);
  }
public static @Nullable PyType getCallType(@NotNull PyBinaryExpression binaryExpression,
                                             @NotNull TypeEvalContext context,
                                             @NotNull TypeEvalContext.Key key)