static ObjectType meet(ObjectType obj1, ObjectType obj2) { Preconditions.checkState(areRelatedClasses(obj1.nominalType, obj2.nominalType)); if (obj1 == TOP_OBJECT) { return obj2; } else if (obj2 == TOP_OBJECT) { return obj1; } NominalType resultNomType = NominalType.pickSubclass(obj1.nominalType, obj2.nominalType); FunctionType fn = FunctionType.meet(obj1.fn, obj2.fn); if (!FunctionType.isInhabitable(fn)) { return BOTTOM_OBJECT; } boolean isLoose = obj1.isLoose && obj2.isLoose || fn != null && fn.isLoose(); if (resultNomType != null && resultNomType.isFunction() && fn == null) { fn = obj1.fn == null ? obj2.fn : obj1.fn; isLoose = fn.isLoose(); } PersistentMap<String, Property> props; if (isLoose) { props = joinPropsLoosely(obj1.props, obj2.props); } else { props = meetPropsHelper(false, resultNomType, obj1.props, obj2.props); } if (props == BOTTOM_MAP) { return BOTTOM_OBJECT; } ObjectKind ok = ObjectKind.meet(obj1.objectKind, obj2.objectKind); return new ObjectType(resultNomType, props, fn, isLoose, ok); }
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); }