Пример #1
0
Type Type::operator&(Type rhs) const {
  auto lhs = *this;

  // When intersecting a constant value with another type, the result will be
  // the constant value if the other value is a supertype of the constant, and
  // Bottom otherwise.
  if (lhs.m_hasConstVal) return lhs <= rhs ? lhs : TBottom;
  if (rhs.m_hasConstVal) return rhs <= lhs ? rhs : TBottom;

  auto bits = lhs.m_bits & rhs.m_bits;
  auto ptr = lhs.ptrKind() & rhs.ptrKind();
  auto arrSpec = lhs.arrSpec() & rhs.arrSpec();
  auto clsSpec = lhs.clsSpec() & rhs.clsSpec();

  // Filter out bits and pieces that no longer exist due to other components
  // going to Bottom, starting with bits.
  if (ptr == Ptr::Bottom) bits &= ~kGen;
  if (arrSpec == ArraySpec::Bottom) bits &= ~kArrSpecBits;
  if (clsSpec == ClassSpec::Bottom) bits &= ~kClsSpecBits;

  // ptr
  if ((bits & kGen) == 0) ptr = Ptr::Bottom;

  // specs
  if (!supports(bits, SpecKind::Array)) arrSpec = ArraySpec::Bottom;
  if (!supports(bits, SpecKind::Class)) clsSpec = ClassSpec::Bottom;

  return Type{bits, ptr}.specialize({arrSpec, clsSpec});
}
Пример #2
0
TEST(Type, SpecializedObjects) {
  auto const A = SystemLib::s_IteratorClass;
  auto const B = SystemLib::s_TraversableClass;
  EXPECT_TRUE(A->classof(B));

  auto const obj = TObj;
  auto const exactA = Type::ExactObj(A);
  auto const exactB = Type::ExactObj(B);
  auto const subA = Type::SubObj(A);
  auto const subB = Type::SubObj(B);

  EXPECT_EQ(exactA.clsSpec().cls(), A);
  EXPECT_EQ(subA.clsSpec().cls(), A);

  EXPECT_EQ(exactA.clsSpec().exactCls(), A);
  EXPECT_EQ(subA.clsSpec().exactCls(), nullptr);

  EXPECT_LE(exactA, exactA);
  EXPECT_LE(subA, subA);

  EXPECT_LT(exactA, obj);
  EXPECT_LT(subA, obj);

  EXPECT_LE(TBottom, subA);
  EXPECT_LE(TBottom, exactA);

  EXPECT_LT(exactA, subA);

  EXPECT_LT(exactA, subB);
  EXPECT_LT(subA, subB);

  EXPECT_FALSE(exactA <= exactB);
  EXPECT_FALSE(subA <= exactB);

  EXPECT_EQ(exactA & subA, exactA);
  EXPECT_EQ(subA & exactA, exactA);
  EXPECT_EQ(exactB & subB, exactB);
  EXPECT_EQ(subB & exactB, exactB);

  EXPECT_EQ(TObj, TObj - subA);  // conservative
  EXPECT_EQ(subA, subA - exactA);  // conservative
}
Пример #3
0
Type Type::operator-(Type rhs) const {
  auto lhs = *this;
  if (rhs == TBottom) return lhs;
  if (lhs <= rhs) return TBottom;
  if (lhs.hasConstVal()) return lhs;    // not covered by rhs.

  // If `rhs' has a constant value, but `lhs' doesn't, conservatively return
  // `lhs', rather than trying to represent things like "everything except
  // Int<24>". Boolean is a special case.
  if (rhs.m_hasConstVal) {
    if (rhs <= TBool && lhs <= TBool) {
      auto const res = !rhs.boolVal();
      if (lhs.hasConstVal() && lhs.boolVal() != res) return TBottom;
      return cns(res);
    }
    return lhs;
  }

  // For each component C, we should subtract C_rhs from C_lhs iff every other
  // component of lhs that can intersect with C is subsumed by the
  // corresponding component of rhs. This prevents us from removing members of
  // lhs that weren't present in rhs, but would be casualties of removing
  // certain bits in lhs.
  //
  // As an example, consider PtrToRMembInt - PtrToRefStr. Simple subtraction of
  // each component would yield PtrToMembInt, but that would mean we removed
  // PtrToRefInt from the lhs despite it not being in rhs. Checking if Int is a
  // subset of Str shows us that removing Ref from lhs would erase types not
  // present in rhs.
  //
  // In practice, it's more concise to eagerly do each subtraction, then check
  // for components that went to Bottom as a way of seeing which components of
  // lhs were subsets of the corresponding components in rhs. When we find a
  // component that we weren't supposed to subtract, just restore lhs's
  // original value.
  auto bits = lhs.m_bits & ~rhs.m_bits;
  auto ptr = lhs.ptrKind() - rhs.ptrKind();
  auto arrSpec = lhs.arrSpec() - rhs.arrSpec();
  auto clsSpec = lhs.clsSpec() - rhs.clsSpec();

  auto const have_gen_bits = (bits & kGen) != 0;
  auto const have_arr_bits = supports(bits, SpecKind::Array);
  auto const have_cls_bits = supports(bits, SpecKind::Class);
  auto const have_ptr      = ptr != Ptr::Bottom;
  auto const have_arr_spec = arrSpec != ArraySpec::Bottom;
  auto const have_cls_spec = clsSpec != ClassSpec::Bottom;

  // ptr can only interact with clsSpec if lhs.m_bits has at least one kGen
  // member of kClsSpecBits.
  auto const have_ptr_cls = supports(lhs.m_bits & kGen, SpecKind::Class);

  // bits
  if (have_ptr) bits |= lhs.m_bits & kGen;
  if (have_arr_spec) bits |= lhs.m_bits & kArrSpecBits;
  if (have_cls_spec) bits |= lhs.m_bits & kClsSpecBits;

  // ptr
  if (have_gen_bits || have_arr_spec || (have_cls_spec && have_ptr_cls)) {
    ptr = lhs.ptrKind();
  }

  // specs
  if (have_ptr || have_arr_bits) arrSpec = lhs.arrSpec();
  if ((have_ptr && have_ptr_cls) || have_cls_bits) clsSpec = lhs.clsSpec();

  return Type{bits, ptr}.specialize({arrSpec, clsSpec});
}