public static boolean typesAgree(@NotNull final PsiType typeLeft,
                                   @NotNull final PsiType typeRight,
                                   final boolean allowUncheckedConversion) {
    if (typeLeft instanceof PsiWildcardType) {
      final PsiWildcardType leftWildcard = (PsiWildcardType)typeLeft;
      final PsiType leftBound = leftWildcard.getBound();
      if (leftBound == null) return true;
      if (leftBound.equalsToText(JAVA_LANG_OBJECT)) {
        if (!leftWildcard.isSuper()) return true;
        if (typeRight.equalsToText(JAVA_LANG_OBJECT)) return true;
      }

      if (typeRight instanceof PsiWildcardType) {
        final PsiWildcardType rightWildcard = (PsiWildcardType)typeRight;
        PsiType bound = rightWildcard.getBound();
        if (leftWildcard.isExtends() && bound != null) {
          return rightWildcard.isExtends() && isAssignable(leftBound, bound, allowUncheckedConversion, false);
        }
        else { //isSuper
          if (rightWildcard.isSuper() && bound != null) {
            NotNullComputable<Boolean> checkAssignable = () -> isAssignable(bound, leftBound, allowUncheckedConversion, false);
            final Boolean assignable = ourGuard.doPreventingRecursion(rightWildcard, true, checkAssignable);
            return assignable != null && assignable;
          }
          return false;
        }
      }
      else {
        if (leftWildcard.isExtends()) {
          return isAssignable(leftBound, typeRight, false, false);
        }
        else { // isSuper
          NotNullComputable<Boolean> checkAssignable = () -> isAssignable(typeRight, leftBound, false, false);
          final Boolean assignable = ourGuard.doPreventingRecursion(leftWildcard, true, checkAssignable);
          return assignable == null || assignable.booleanValue();
        }
      }
    }
    else {
      return typeLeft.equals(typeRight);
    }
  }
public static boolean typesAgree(@NotNull final PsiType typeLeft,
                                   @NotNull final PsiType typeRight,
                                   final boolean allowUncheckedConversion)