private Binding unify(final PsiType x, final PsiType y, final Unifier unifier) {
    final int indicator = (x instanceof PsiTypeVariable ? 1 : 0) + (y instanceof PsiTypeVariable ? 2 : 0);

    if (indicator == 0) {
      if (x instanceof PsiWildcardType || y instanceof PsiWildcardType) {
        return unifier.unify(x, y);
      }
      else if (x instanceof PsiArrayType || y instanceof PsiArrayType) {
        final PsiType xType = x instanceof PsiArrayType ? ((PsiArrayType)x).getComponentType() : x;
        final PsiType yType = y instanceof PsiArrayType ? ((PsiArrayType)y).getComponentType() : y;

        return unify(xType, yType, unifier);
      }
      else if (x instanceof PsiClassType && y instanceof PsiClassType) {
        final PsiClassType.ClassResolveResult resultX = Util.resolveType(x);
        final PsiClassType.ClassResolveResult resultY = Util.resolveType(y);

        final PsiClass xClass = resultX.getElement();
        final PsiClass yClass = resultY.getElement();

        if (xClass != null && yClass != null) {
          final PsiSubstitutor ySubst = resultY.getSubstitutor();

          final PsiSubstitutor xSubst = resultX.getSubstitutor();

          if (!xClass.equals(yClass)) {
            return null;
          }

          Binding b = create();

          for (final PsiTypeParameter aParm : xSubst.getSubstitutionMap().keySet()) {
            final PsiType xType = xSubst.substitute(aParm);
            final PsiType yType = ySubst.substitute(aParm);

            final Binding b1 = unify(xType, yType, unifier);

            if (b1 == null) {
              return null;
            }

            b = b.compose(b1);
          }

          return b;
        }
      }
      else if (y instanceof Bottom) {
        return create();
      }
      else {
        return null;
      }
    }
    return unifier.unify(x, y);
  }
private Binding unify(final PsiType x, final PsiType y, final Unifier unifier)