ObjectType specialize(ObjectType other) { Preconditions.checkState(areRelatedClasses(this.nominalType, other.nominalType)); if (this == TOP_OBJECT && other.objectKind.isUnrestricted()) { return other; } NominalType resultNomType = NominalType.pickSubclass(this.nominalType, other.nominalType); ObjectKind ok = ObjectKind.meet(this.objectKind, other.objectKind); if (resultNomType != null && resultNomType.isClassy()) { Preconditions.checkState(this.fn == null && other.fn == null); PersistentMap<String, Property> newProps = meetPropsHelper(true, resultNomType, this.props, other.props); if (newProps == BOTTOM_MAP) { return BOTTOM_OBJECT; } return new ObjectType(resultNomType, newProps, null, false, ok); } FunctionType thisFn = this.fn; boolean isLoose = this.isLoose; if (resultNomType != null && resultNomType.isFunction() && this.fn == null) { thisFn = other.fn; isLoose = other.fn.isLoose(); } PersistentMap<String, Property> newProps = meetPropsHelper(true, resultNomType, this.props, other.props); if (newProps == BOTTOM_MAP) { return BOTTOM_OBJECT; } FunctionType newFn = thisFn == null ? null : thisFn.specialize(other.fn); if (!FunctionType.isInhabitable(newFn)) { return BOTTOM_OBJECT; } return new ObjectType(resultNomType, newProps, newFn, isLoose, ok); }