private @Nls String incompatibleBoundsMessage(final InferenceVariable var,
                                                final PsiSubstitutor substitutor,
                                                final InferenceBound lowBound,
                                                final String lowBoundName,
                                                final InferenceBound upperBound,
                                                final String upperBoundName) {
    final Function<PsiType, String> typePresentation = type -> {
      final PsiType substituted = substituteNonProperBound(type, substitutor);
      return getPresentableText(substituted != null ? substituted : type);
    };
    return JavaPsiBundle.message("error.inference.variable.has.incompatible.bounds", 
                                 var.getParameter().getName(), lowBoundName, 
                                 StringUtil.join(var.getBounds(lowBound), typePresentation, ", "), upperBoundName, 
                                 StringUtil.join(var.getBounds(upperBound), typePresentation, ", "));
  }
private @Nls String incompatibleBoundsMessage(final InferenceVariable var,
                                                final PsiSubstitutor substitutor,
                                                final InferenceBound lowBound,
                                                final String lowBoundName,
                                                final InferenceBound upperBound,
                                                final String upperBoundName)