@Override
  public @NotNull DfType join(@NotNull DfType other) {
    if (other == DfType.BOTTOM) return this;
    if (other == DfType.TOP || !(other instanceof DfReferenceType)) return DfType.TOP;
    TypeConstraint otherConstraint = ((DfReferenceType)other).getConstraint();
    TypeConstraint constraint = myTypeConstraint.join(otherConstraint);
    if (other instanceof DfEphemeralReferenceType) {
      return constraint == myTypeConstraint ? this :
             constraint == otherConstraint ? other :
             constraint == TypeConstraints.TOP ? DfTypes.NOT_NULL_OBJECT :
             new DfEphemeralReferenceType(constraint);
    }
    Set<Object> notValues = other instanceof DfGenericObjectType ? ((DfGenericObjectType)other).getRawNotValues() : Set.of();
    return new DfGenericObjectType(notValues, constraint, ((DfReferenceType)other).getNullability(),
                                   Mutability.UNKNOWN, null, DfType.BOTTOM, false);
  }
@Override
  public @NotNull DfType join(@NotNull DfType other)