AliasClass AliasClass::operator|(AliasClass o) const { if (auto const c = precise_union(o)) return *c; auto const unioned = static_cast<rep>(m_bits | o.m_bits); // If they have the same stag, try to merge them with unionData. auto stag1 = m_stag; auto stag2 = o.m_stag; if (stag1 == stag2) return unionData(unioned, *this, o); // If one of the alias classes have a non-None stag, we can only keep it if // the other doesn't have the corresponding bit set. if (stag1 != STag::None && (o.m_bits & stagBit(stag1))) stag1 = STag::None; if (stag2 != STag::None && (m_bits & stagBit(stag2))) stag2 = STag::None; auto ret = AliasClass{unioned}; if (stag1 == stag2) return ret; // both None. // Note: union operations are guaranteed to be commutative, so if there are // two non-None stags, we have to consistently choose between them. For now // we keep the one with a smaller `rep' value, instead of discarding both. const AliasClass* chosen = &o; auto stag = stag2; if (stag1 != STag::None) { if (stag2 == STag::None || stagBit(stag1) < stagBit(stag2)) { chosen = this; stag = stag1; } } switch (stag) { case STag::None: break; case STag::Frame: new (&ret.m_frame) AFrame(chosen->m_frame); break; case STag::Prop: new (&ret.m_prop) AProp(chosen->m_prop); break; case STag::ElemI: new (&ret.m_elemI) AElemI(chosen->m_elemI); break; case STag::ElemS: new (&ret.m_elemS) AElemS(chosen->m_elemS); break; case STag::Stack: new (&ret.m_stack) AStack(chosen->m_stack); break; case STag::MIState: new (&ret.m_mis) AMIState(chosen->m_mis); break; case STag::Ref: new (&ret.m_ref) ARef(chosen->m_ref); break; } ret.m_stag = stag; return ret; }
AliasClass AliasClass::operator|(AliasClass o) const { if (o <= *this) return *this; if (*this <= o) return o; auto const unioned = static_cast<rep>(m_bits | o.m_bits); // Note: union operations are guaranteed to be commutative, so if there are // two non-None stags, we have to consistently choose between them. For now // we throw both away in any case where they differ, and try to merge them // with unionData if they are the same. If only one had an stag, we can keep // it only if the other didn't have that bit set. auto const stag1 = m_stag; auto const stag2 = o.m_stag; if (stag1 == stag2) return unionData(unioned, *this, o); if (stag1 != STag::None && stag2 != STag::None) { return AliasClass{unioned}; } if (stag2 != STag::None) return o | *this; if (o.m_bits & stagBit(stag1)) { return AliasClass{unioned}; } auto ret = AliasClass{unioned}; switch (stag1) { case STag::None: break; case STag::Frame: new (&ret.m_frame) AFrame(m_frame); break; case STag::Prop: new (&ret.m_prop) AProp(m_prop); break; case STag::ElemI: new (&ret.m_elemI) AElemI(m_elemI); break; case STag::ElemS: new (&ret.m_elemS) AElemS(m_elemS); break; case STag::Stack: new (&ret.m_stack) AStack(m_stack); break; case STag::MIState: new (&ret.m_mis) AMIState(m_mis); break; } ret.m_stag = stag1; return ret; }