Skip to content

Commit d4f85a3

Browse files
committed
AST: Fix odd behavior of Type::canonicalizeProtocols() with circular inheritance
If an invalid protocol P inherited from itself, then canonicalizing {P} would produce an empty list. This broke another assertion I'm working on.
1 parent fd7759f commit d4f85a3

File tree

1 file changed

+24
-52
lines changed

1 file changed

+24
-52
lines changed

lib/AST/Type.cpp

Lines changed: 24 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1163,38 +1163,6 @@ static void addProtocols(Type T,
11631163
Superclass = T;
11641164
}
11651165

1166-
/// Add the protocol (or protocols) in the type T to the stack of
1167-
/// protocols, checking whether any of the protocols had already been seen and
1168-
/// zapping those in the original list that we find again.
1169-
static void
1170-
addMinimumProtocols(Type T, SmallVectorImpl<ProtocolDecl *> &Protocols,
1171-
llvm::SmallDenseMap<ProtocolDecl *, unsigned> &Known,
1172-
llvm::SmallPtrSetImpl<ProtocolDecl *> &Visited,
1173-
SmallVector<ProtocolDecl *, 16> &Stack, bool &ZappedAny) {
1174-
if (auto Proto = T->getAs<ProtocolType>()) {
1175-
auto KnownPos = Known.find(Proto->getDecl());
1176-
if (KnownPos != Known.end()) {
1177-
// We've come across a protocol that is in our original list. Zap it.
1178-
Protocols[KnownPos->second] = nullptr;
1179-
ZappedAny = true;
1180-
}
1181-
1182-
if (Visited.insert(Proto->getDecl()).second) {
1183-
Stack.push_back(Proto->getDecl());
1184-
for (auto Inherited : Proto->getDecl()->getInheritedProtocols())
1185-
addMinimumProtocols(Inherited->getDeclaredInterfaceType(),
1186-
Protocols, Known, Visited, Stack, ZappedAny);
1187-
}
1188-
return;
1189-
}
1190-
1191-
if (auto PC = T->getAs<ProtocolCompositionType>()) {
1192-
for (auto C : PC->getMembers()) {
1193-
addMinimumProtocols(C, Protocols, Known, Visited, Stack, ZappedAny);
1194-
}
1195-
}
1196-
}
1197-
11981166
bool ProtocolType::visitAllProtocols(
11991167
ArrayRef<ProtocolDecl *> protocols,
12001168
llvm::function_ref<bool(ProtocolDecl *)> fn) {
@@ -1229,44 +1197,48 @@ bool ProtocolType::visitAllProtocols(
12291197
void ProtocolType::canonicalizeProtocols(
12301198
SmallVectorImpl<ProtocolDecl *> &protocols) {
12311199
llvm::SmallDenseMap<ProtocolDecl *, unsigned> known;
1232-
llvm::SmallPtrSet<ProtocolDecl *, 16> visited;
1233-
SmallVector<ProtocolDecl *, 16> stack;
12341200
bool zappedAny = false;
12351201

12361202
// Seed the stack with the protocol declarations in the original list.
12371203
// Zap any obvious duplicates along the way.
1238-
for (unsigned I = 0, N = protocols.size(); I != N; ++I) {
1239-
// Check whether we've seen this protocol before.
1240-
auto knownPos = known.find(protocols[I]);
1241-
1204+
for (unsigned i : indices(protocols)) {
12421205
// If we have not seen this protocol before, record its index.
1243-
if (knownPos == known.end()) {
1244-
known[protocols[I]] = I;
1245-
stack.push_back(protocols[I]);
1206+
if (known.count(protocols[i]) == 0) {
1207+
known[protocols[i]] = i;
12461208
continue;
12471209
}
1248-
1210+
12491211
// We have seen this protocol before; zap this occurrence.
1250-
protocols[I] = nullptr;
1212+
protocols[i] = nullptr;
12511213
zappedAny = true;
12521214
}
12531215

12541216
// Walk the inheritance hierarchies of all of the protocols. If we run into
12551217
// one of the known protocols, zap it from the original list.
1256-
while (!stack.empty()) {
1257-
ProtocolDecl *Current = stack.back();
1258-
stack.pop_back();
1259-
1218+
for (unsigned i : indices(protocols)) {
1219+
auto *proto = protocols[i];
1220+
if (proto == nullptr)
1221+
continue;
1222+
12601223
// Add the protocols we inherited.
1261-
for (auto Inherited : Current->getInheritedProtocols()) {
1262-
addMinimumProtocols(Inherited->getDeclaredInterfaceType(),
1263-
protocols, known, visited, stack, zappedAny);
1264-
}
1224+
proto->walkInheritedProtocols([&](ProtocolDecl *inherited) {
1225+
if (inherited == proto)
1226+
return TypeWalker::Action::Continue;
1227+
1228+
auto found = known.find(inherited);
1229+
if (found != known.end()) {
1230+
protocols[found->second] = nullptr;
1231+
zappedAny = true;
1232+
}
1233+
1234+
return TypeWalker::Action::Continue;
1235+
});
12651236
}
12661237

1267-
if (zappedAny)
1238+
if (zappedAny) {
12681239
protocols.erase(std::remove(protocols.begin(), protocols.end(), nullptr),
12691240
protocols.end());
1241+
}
12701242

12711243
// Sort the set of protocols by module + name, to give a stable
12721244
// ordering.

0 commit comments

Comments
 (0)