Type Type::operator|(Type b) const { auto a = *this; // Representing types like {Int<12>|Arr} could get messy and isn't useful in // practice, so unless we're unioning a constant type with itself or Bottom, // drop the constant value(s). if (a == b || b == Bottom) return a; if (a == Bottom) return b; a = a.dropConstVal(); b = b.dropConstVal(); return combine<Union>(a.m_bits | b.m_bits, a, b); }
Type Type::operator|(Type rhs) const { auto lhs = *this; if (lhs == rhs || rhs == TBottom) return lhs; if (lhs == TBottom) return rhs; // Representing types like {Int<12>|Arr} could get messy and isn't useful in // practice, so unless we hit one of the trivial cases above, drop the // constant value(s). lhs = lhs.dropConstVal(); rhs = rhs.dropConstVal(); auto const bits = lhs.m_bits | rhs.m_bits; auto const ptr = lhs.ptrKind() | rhs.ptrKind(); auto const spec = lhs.spec() | rhs.spec(); return Type{bits, ptr}.specialize(spec); }
TEST(Type, Const) { auto five = Type::cns(5); EXPECT_LT(five, Type::Int); EXPECT_NE(five, Type::Int); EXPECT_TRUE(five.isConst()); EXPECT_EQ(5, five.intVal()); EXPECT_TRUE(five.isConst(Type::Int)); EXPECT_TRUE(five.isConst(5)); EXPECT_FALSE(five.isConst(5.0)); EXPECT_TRUE(Type::Gen.maybe(five)); EXPECT_EQ(Type::Int, five | Type::Int); EXPECT_EQ(Type::Int, five | Type::cns(10)); EXPECT_EQ(five, five | Type::cns(5)); EXPECT_EQ(five, Type::cns(5) & five); EXPECT_EQ(five, five & Type::Int); EXPECT_EQ(five, Type::Gen & five); EXPECT_EQ("Int<5>", five.toString()); EXPECT_EQ(five, five - Type::Arr); EXPECT_EQ(five, five - Type::cns(1)); EXPECT_EQ(Type::Bottom, five - Type::Int); EXPECT_EQ(Type::Bottom, five - five); EXPECT_EQ(Type::Int, five.dropConstVal()); EXPECT_TRUE(five.not(Type::cns(2))); auto True = Type::cns(true); EXPECT_EQ("Bool<true>", True.toString()); EXPECT_LT(True, Type::Bool); EXPECT_NE(True, Type::Bool); EXPECT_TRUE(True.isConst()); EXPECT_EQ(true, True.boolVal()); EXPECT_TRUE(Type::Uncounted.maybe(True)); EXPECT_FALSE(five <= True); EXPECT_FALSE(five > True); EXPECT_TRUE(five.not(True)); EXPECT_EQ(Type::Int | Type::Bool, five | True); EXPECT_EQ(Type::Bottom, five & True); EXPECT_TRUE(Type::Uninit.isConst()); EXPECT_TRUE(Type::InitNull.isConst()); EXPECT_FALSE(Type::Null.isConst()); EXPECT_FALSE((Type::Uninit | Type::Bool).isConst()); EXPECT_FALSE(Type::Int.isConst()); }
TEST(Type, Const) { auto five = Type::cns(5); EXPECT_LT(five, Type::Int); EXPECT_NE(five, Type::Int); EXPECT_TRUE(five.isConst()); EXPECT_EQ(5, five.intVal()); EXPECT_TRUE(five.isConst(Type::Int)); EXPECT_TRUE(five.isConst(5)); EXPECT_FALSE(five.isConst(5.0)); EXPECT_TRUE(Type::Gen.maybe(five)); EXPECT_EQ(Type::Int, five | Type::Int); EXPECT_EQ(Type::Int, five | Type::cns(10)); EXPECT_EQ(five, five | Type::cns(5)); EXPECT_EQ(five, Type::cns(5) & five); EXPECT_EQ(five, five & Type::Int); EXPECT_EQ(five, Type::Gen & five); EXPECT_EQ("Int<5>", five.toString()); EXPECT_EQ(five, five - Type::Arr); EXPECT_EQ(five, five - Type::cns(1)); EXPECT_EQ(Type::Int, Type::Int - five); // conservative EXPECT_EQ(Type::Bottom, five - Type::Int); EXPECT_EQ(Type::Bottom, five - five); EXPECT_EQ(Type::PtrToGen, (Type::PtrToGen|Type::Nullptr) - Type::Nullptr); EXPECT_EQ(Type::Int, five.dropConstVal()); EXPECT_TRUE(five.not(Type::cns(2))); auto True = Type::cns(true); EXPECT_EQ("Bool<true>", True.toString()); EXPECT_LT(True, Type::Bool); EXPECT_NE(True, Type::Bool); EXPECT_TRUE(True.isConst()); EXPECT_EQ(true, True.boolVal()); EXPECT_TRUE(Type::Uncounted.maybe(True)); EXPECT_FALSE(five <= True); EXPECT_FALSE(five > True); EXPECT_TRUE(five.not(True)); EXPECT_EQ(Type::Int | Type::Bool, five | True); EXPECT_EQ(Type::Bottom, five & True); EXPECT_TRUE(Type::Uninit.isConst()); EXPECT_TRUE(Type::InitNull.isConst()); EXPECT_FALSE(Type::Null.isConst()); EXPECT_FALSE((Type::Uninit | Type::Bool).isConst()); EXPECT_FALSE(Type::Int.isConst()); auto array = make_packed_array(1, 2, 3, 4); auto arrData = ArrayData::GetScalarArray(array.get()); auto constArray = Type::cns(arrData); auto packedArray = Type::Arr.specialize(ArrayData::kPackedKind); auto mixedArray = Type::Arr.specialize(ArrayData::kMixedKind); EXPECT_TRUE(constArray <= packedArray); EXPECT_TRUE(constArray < packedArray); EXPECT_FALSE(packedArray <= constArray); EXPECT_TRUE(constArray <= constArray); EXPECT_FALSE(packedArray <= mixedArray); EXPECT_FALSE(mixedArray <= packedArray); EXPECT_FALSE(constArray <= mixedArray); EXPECT_EQ(constArray, constArray & packedArray); ArrayTypeTable::Builder ratBuilder; auto rat1 = ratBuilder.packedn(RepoAuthType::Array::Empty::No, RepoAuthType(RepoAuthType::Tag::Str)); auto ratArray1 = Type::Arr.specialize(rat1); auto rat2 = ratBuilder.packedn(RepoAuthType::Array::Empty::No, RepoAuthType(RepoAuthType::Tag::Int)); auto ratArray2 = Type::Arr.specialize(rat2); EXPECT_EQ(Type::Arr, ratArray1 & ratArray2); EXPECT_TRUE(ratArray1 < Type::Arr); EXPECT_TRUE(ratArray1 <= ratArray1); EXPECT_TRUE(ratArray1 < (Type::Arr|Type::Obj)); EXPECT_FALSE(ratArray1 < ratArray2); EXPECT_NE(ratArray1, ratArray2); auto packedRat = packedArray & ratArray1; EXPECT_EQ("Arr=PackedKind:N([Str])", packedRat.toString()); EXPECT_TRUE(packedRat <= packedArray); EXPECT_TRUE(packedRat < packedArray); EXPECT_TRUE(packedRat <= ratArray1); EXPECT_TRUE(packedRat < ratArray1); EXPECT_EQ(packedRat, packedRat & packedArray); EXPECT_EQ(packedRat, packedRat & ratArray1); }