RuntimeType Type::toRuntimeType() const { assert(!isPtr()); auto const outer = isBoxed() ? KindOfRef : toDataType(); auto const inner = isBoxed() ? innerType().toDataType() : KindOfNone; auto rtt = RuntimeType{outer, inner}; if (isSpecialized()) { if (subtypeOf(Type::Arr)) { return rtt.setArrayKind(getArrayKind()); } else if (subtypeOf(Type::Obj)) { return rtt.setKnownClass(getClass()); } } return rtt; }
Type Type::combine(bits_t newBits, Type other) const { static_assert(std::is_same<Oper, Union>::value || std::is_same<Oper, Intersect>::value, "Type::combine given unsupported template argument"); // If neither type is specialized, the result is simple. if (LIKELY(!isSpecialized() && !other.isSpecialized())) { return Type(newBits); } // If one of the types can't be specialized while the other is specialized, // preserve the specialization. if (!canSpecializeAny() || !other.canSpecializeAny()) { auto const specType = isSpecialized() ? specializedType() : other.specializedType(); // If the specialized type doesn't exist in newBits, drop the // specialization. if (newBits & specType.m_bits) return Type(newBits, specType.m_extra); return Type(newBits); } // If both types are eligible for the same kind of specialization and at // least one is specialized, delegate to Oper::combineSame. if (canSpecializeClass() && other.canSpecializeClass()) { folly::Optional<const Class*> aClass, bClass; if (getClass()) aClass = getClass(); if (other.getClass()) bClass = other.getClass(); return Oper::template combineSame<ClassOps>(newBits, kAnyObj, aClass, bClass); } if (canSpecializeArrayKind() && other.canSpecializeArrayKind()) { folly::Optional<ArrayData::ArrayKind> aKind, bKind; if (hasArrayKind()) aKind = getArrayKind(); if (other.hasArrayKind()) bKind = other.getArrayKind(); return Oper::template combineSame<ArrayOps>(newBits, kAnyArr, aKind, bKind); } // The types are eligible for different kinds of specialization and at least // one is specialized, so delegate to Oper::combineDifferent. return Oper::combineDifferent(newBits, *this, other); }
Type Type::operator-(Type other) const { auto const newBits = m_bits & ~other.m_bits; if (m_hasConstVal) { // If other is a constant of the same type, the result is Bottom or this // depending on whether or not it's the same constant. if (other.m_bits == m_bits && other.m_hasConstVal) { return other.m_extra == m_extra ? Bottom : *this; } // Otherwise, just check to see if the constant's type was removed in // newBits. return (newBits & m_bits) ? *this : Bottom; } // Rather than try to represent types like "all Ints except 24", treat t - // Int<24> as t - Int. other = other.dropConstVal(); auto const spec1 = isSpecialized(); auto const spec2 = other.isSpecialized(); // The common easy case is when neither type is specialized. if (LIKELY(!spec1 && !spec2)) return Type(newBits); if (spec1 && spec2) { if (canSpecializeClass() != other.canSpecializeClass()) { // Both are specialized but in different ways. Our specialization is // preserved. return Type(newBits, m_extra); } // Subtracting different specializations of the same type could get messy // so we don't support it for now. always_assert(specializedType() == other.specializedType() && "Incompatible specialized types given to operator-"); // If we got here, both types have the same specialization, so it's removed // from the result. return Type(newBits); } // If masking out other's bits removed all of the bits that correspond to our // specialization, take it out. Otherwise, preserve it. if (spec1) { if (canSpecializeClass()) { if (!(newBits & kAnyObj)) return Type(newBits); return Type(newBits, m_class); } if (canSpecializeArrayKind()) { if (!(newBits & kAnyArr)) return Type(newBits); return Type(newBits, getArrayKind()); } not_reached(); } // Only other is specialized. This is where things get a little fuzzy. We // want to be able to support things like Obj - Obj<C> but we can't represent // Obj<~C>. We compromise and return Bottom in cases like this, which means // we need to be careful because (a - b) == Bottom doesn't imply a <= b in // this world. if (other.canSpecializeClass()) return Type(newBits & ~kAnyObj); return Type(newBits & ~kAnyArr); }