Skip to content

Commit e4faf73

Browse files
committed
RequirementMachine: Fix another bug in checkForOverlap()
The `if (other.size() > size())` check was bogus; we can still have an overlap of the second kind if the other term is longer than this term. Remove this check, and rewrite the algorithm to be clearer in general.
1 parent 8da15f8 commit e4faf73

File tree

1 file changed

+56
-42
lines changed

1 file changed

+56
-42
lines changed

lib/AST/RequirementMachine/RewriteSystemCompletion.cpp

Lines changed: 56 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -85,61 +85,75 @@ OverlapKind
8585
MutableTerm::checkForOverlap(const MutableTerm &other,
8686
MutableTerm &t,
8787
MutableTerm &v) const {
88-
// If the other term is longer than this term, there's no way
89-
// we can overlap.
90-
if (other.size() > size())
91-
return OverlapKind::None;
92-
93-
auto first1 = begin();
94-
auto last1 = end();
95-
auto first2 = other.begin();
96-
auto last2 = other.end();
97-
98-
// Look for an overlap of the first kind, where the other term is
99-
// wholly contained in this term.
100-
//
101-
// A.B.C.D.E
102-
// X.Y.Z
103-
// X.Y.Z
104-
// X.Y.Z
105-
while (last1 - first1 >= last2 - first2) {
106-
if (std::equal(first2, last2, first1)) {
107-
// We have an overlap of the first kind, where
108-
// this == TUV and other == U.
109-
//
110-
// Get the subterms for T and V.
111-
t = MutableTerm(begin(), first1);
112-
v = MutableTerm(first1 + other.size(), end());
113-
return OverlapKind::First;
114-
}
88+
assert(!empty());
89+
assert(!other.empty());
90+
91+
if (*this == other) {
92+
// If this term is equal to the other term, we have an overlap.
93+
t = MutableTerm();
94+
v = MutableTerm();
95+
return OverlapKind::First;
96+
}
11597

116-
++first1;
98+
if (size() > other.size()) {
99+
// If this term is longer than the other term, check if it contains
100+
// the other term.
101+
auto first1 = begin();
102+
while (first1 <= end() - other.size()) {
103+
if (std::equal(other.begin(), other.end(), first1)) {
104+
// We have an overlap.
105+
t = MutableTerm(begin(), first1);
106+
v = MutableTerm(first1 + other.size(), end());
107+
108+
// If both T and V are empty, we have two equal terms, which
109+
// should have been handled above.
110+
assert(!t.empty() || !v.empty());
111+
assert(t.size() + other.size() + v.size() == size());
112+
113+
return OverlapKind::First;
114+
}
115+
116+
++first1;
117+
}
117118
}
118119

119-
// Look for an overlap of the second kind, where a prefix of the
120-
// other term is equal to some suffix of this term.
120+
// Finally, check if a suffix of this term is equal to a prefix of
121+
// the other term.
122+
unsigned count = std::min(size(), other.size());
123+
auto first1 = end() - count;
124+
auto last2 = other.begin() + count;
125+
126+
// Initial state, depending on size() <=> other.size():
121127
//
122-
// A.B.C.D.E
123-
// X.Y
124-
// X
125-
while (first1 != last1) {
126-
--last2;
128+
// ABC -- count = 3, first1 = this[0], last2 = other[3]
129+
// XYZ
130+
//
131+
// ABC -- count = 2, first1 = this[1], last2 = other[2]
132+
// XY
133+
//
134+
// ABC -- count = 3, first1 = this[0], last2 = other[3]
135+
// XYZW
127136

128-
if (std::equal(first1, last1, first2)) {
129-
// We have an overlap of the second kind, where
130-
// this == TU and other == UV.
131-
//
132-
// Get the subterms for T and V.
137+
// Advance by 1, since we don't need to check for full containment
138+
++first1;
139+
--last2;
140+
141+
while (last2 != other.begin()) {
142+
if (std::equal(other.begin(), last2, first1)) {
133143
t = MutableTerm(begin(), first1);
134-
assert(!t.empty());
135144
v = MutableTerm(last2, other.end());
145+
146+
assert(!t.empty());
147+
assert(!v.empty());
148+
assert(t.size() + other.size() - v.size() == size());
149+
136150
return OverlapKind::Second;
137151
}
138152

139153
++first1;
154+
--last2;
140155
}
141156

142-
// No overlap found.
143157
return OverlapKind::None;
144158
}
145159

0 commit comments

Comments
 (0)