private DfType join(@NotNull DfType other, boolean exact) {
    if (other.isSuperType(this)) return other;
    if (other instanceof DfFloatRangeType) {
      return ((DfFloatRangeType)other).join(this, exact);
    }
    if (other instanceof DfFloatConstantType) {
      float val1 = getValue();
      float val2 = ((DfFloatConstantType)other).getValue();
      if (Float.isNaN(val1)) {
        return DfFloatRangeType.create(val2, val2, false, true);
      }
      if (Float.isNaN(val2)) {
        return DfFloatRangeType.create(val1, val1, false, true);
      }
      float from = Math.min(val1, val2);
      float to = Math.max(val1, val2);
      // We don't support disjoint sets, so the best we can do is to return a range from min to max
      return exact ? null : DfFloatRangeType.create(from, to, false, false);
    }
    return exact ? null : DfType.TOP;
  }
private DfType join(@NotNull DfType other, boolean exact)