DfType (@NotNull DfType other) { if (isSuperType(other)) return this; if (other.isSuperType(this)) return other; if (!(other instanceof DfReferenceType type)) return TOP; if (other instanceof DfNullConstantType || other instanceof DfEphemeralReferenceType) { return other.join(this); } TypeConstraint constraint = getConstraint().join(type.getConstraint()); if (constraint == TypeConstraints.BOTTOM) { throw new AssertionError("Join failed: " + this + " | " + other); } DfaNullability nullability = getNullability().unite(type.getNullability()); Mutability mutability = getMutability().join(type.getMutability()); boolean locality = isLocal() && type.isLocal(); SpecialField sf = Objects.equals(getSpecialField(), type.getSpecialField()) ? getSpecialField() : null; DfType sfType = sf == null ? BOTTOM : getSpecialFieldType().join(type.getSpecialFieldType()); Set<Object> notValues = myNotValues; if (type instanceof DfGenericObjectType) { notValues = new HashSet<>(myNotValues); notValues.retainAll(((DfGenericObjectType)other).myNotValues); } if (type instanceof DfReferenceConstantType) { notValues = new HashSet<>(myNotValues); notValues.remove(((DfReferenceConstantType)type).getValue()); } return new DfGenericObjectType(notValues, constraint, nullability, mutability, sf, sfType, locality); }