bool ArraySpec::operator<=(const ArraySpec& rhs) const { auto const& lhs = *this; if (lhs == Bottom || rhs == Top) return true; if (lhs == Top || rhs == Bottom) return false; // It's possible to subtype RAT::Array types, but it's potentially O(n), so // we just don't do it. return (!rhs.kind() || lhs.kind() == rhs.kind()) && (!rhs.type() || lhs.type() == rhs.type()) && (!rhs.shape() || lhs.shape() == rhs.shape()); }
// Return true if the array satisfies requirement on the ArraySpec. static bool arrayFitsSpec(const ArrayData* arr, const ArraySpec spec) { if (spec == ArraySpec::Top) return true; if (auto const spec_kind = spec.kind()) { if (arr->kind() == spec_kind) return true; } if (auto const rat_type = spec.type()) { using A = RepoAuthType::Array; if (arr->empty() && rat_type->emptiness() != A::Empty::No) return true; if (arr->isVectorData()) { switch (rat_type->tag()) { case A::Tag::Packed: if (arr->size() != rat_type->size()) break; // fall through case A::Tag::PackedN: { int64_t k = 0; for ( ; k < arr->size(); ++k) { auto const specElemType = rat_type->tag() == A::Tag::Packed ? rat_type->packedElem(k) : rat_type->elemType(); if (!tvMatchesRepoAuthType(*(arr->get(k).asTypedValue()), specElemType)) { break; } } if (k == arr->size()) return true; break; } } } } return false; }
ArraySpec ArraySpec::operator|(const ArraySpec& rhs) const { auto const& lhs = *this; if (lhs <= rhs) return rhs; if (rhs <= lhs) return lhs; // Take the union componentwise. Components union trivially (i.e., to // "unspecialized") unless they are equal. auto new_kind = lhs.kind() == rhs.kind() ? lhs.kind() : folly::none; auto new_type = lhs.type() == rhs.type() ? lhs.type() : nullptr; // If the shapes were nontrivial and equal, the specs would be equal. assertx(!lhs.shape() || lhs.shape() != rhs.shape()); // Nontrivial kind /and/ type unions would imply equal kinds and types. assertx(!new_kind || !new_type); if (new_kind) return ArraySpec(*new_kind); if (new_type) return ArraySpec(new_type); return Top; }