Skip to content

Commit 45d0eca

Browse files
committed
ModuleInterface: consider inherited protocols from super class when collecting handled protocols
Protocol conformances can be implied by super classes. When collecting the list of IncludedProtocols, we should traverse the class inheritance chain and collect all protocols. Without this change, these implied conformances will be printed again via a synthesized extension at the end of the Swift interface file, leading to an error of redundant conformances when building modules. rdar://58563540
1 parent a3cf373 commit 45d0eca

File tree

2 files changed

+32
-5
lines changed

2 files changed

+32
-5
lines changed

lib/Frontend/ModuleInterfaceSupport.cpp

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -294,21 +294,26 @@ class InheritedProtocolCollector {
294294
const NominalTypeDecl *nominal;
295295
const IterableDeclContext *memberContext;
296296

297+
auto shouldInclude = [](const ExtensionDecl *extension) {
298+
if (extension->isConstrainedExtension()) {
299+
// Conditional conformances never apply to inherited protocols, nor
300+
// can they provide unconditional conformances that might be used in
301+
// other extensions.
302+
return false;
303+
}
304+
return true;
305+
};
297306
if ((nominal = dyn_cast<NominalTypeDecl>(D))) {
298307
directlyInherited = nominal->getInherited();
299308
memberContext = nominal;
300309

301310
} else if (auto *extension = dyn_cast<ExtensionDecl>(D)) {
302-
if (extension->isConstrainedExtension()) {
303-
// Conditional conformances never apply to inherited protocols, nor
304-
// can they provide unconditional conformances that might be used in
305-
// other extensions.
311+
if (!shouldInclude(extension)) {
306312
return;
307313
}
308314
nominal = extension->getExtendedNominal();
309315
directlyInherited = extension->getInherited();
310316
memberContext = extension;
311-
312317
} else {
313318
return;
314319
}
@@ -317,6 +322,18 @@ class InheritedProtocolCollector {
317322
return;
318323

319324
map[nominal].recordProtocols(directlyInherited, D);
325+
// Collect protocols inherited from super classes
326+
if (auto *CD = dyn_cast<ClassDecl>(D)) {
327+
for (auto *SD = CD->getSuperclassDecl(); SD;
328+
SD = SD->getSuperclassDecl()) {
329+
map[nominal].recordProtocols(SD->getInherited(), SD);
330+
for (auto *Ext: SD->getExtensions()) {
331+
if (shouldInclude(Ext)) {
332+
map[nominal].recordProtocols(Ext->getInherited(), Ext);
333+
}
334+
}
335+
}
336+
}
320337

321338
// Recurse to find any nested types.
322339
for (const Decl *member : memberContext->getMembers())
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -typecheck -module-name Foo -emit-module-interface-path %t/Foo.swiftinterface %s
3+
// RUN: %target-swift-frontend -compile-module-from-interface %t/Foo.swiftinterface -o %t/Foo.swiftmodule
4+
5+
public protocol ProtocolA : class {}
6+
public protocol ProtocolB: ProtocolA {}
7+
protocol ProtocolC: ProtocolA {}
8+
9+
public class A: ProtocolB {}
10+
public class B: A, ProtocolC {}

0 commit comments

Comments
 (0)