Skip to content

Commit 28575b0

Browse files
committed
Sema: Handle nested compositions and parameterized protocols in diagnoseRetroactiveConformances()
1 parent 26f4c7e commit 28575b0

File tree

2 files changed

+43
-22
lines changed

2 files changed

+43
-22
lines changed

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1777,6 +1777,33 @@ static TypeRepr *unwrapAttributedRepr(TypeRepr *repr) {
17771777
return repr;
17781778
}
17791779

1780+
static void collectProtocolsFromInheritedEntry(
1781+
const InheritedEntry &entry,
1782+
Type inheritedTy,
1783+
llvm::SmallPtrSetImpl<ProtocolDecl *> &protocolsWithRetroactiveAttr,
1784+
SmallVectorImpl<ProtocolDecl *> &protos) {
1785+
1786+
if (auto *protoTy = inheritedTy->getAs<ProtocolType>()) {
1787+
auto *proto = protoTy->getDecl();
1788+
1789+
// As a fallback, to support previous language versions, also allow
1790+
// this through if the protocol has been explicitly module-qualified.
1791+
TypeRepr *repr = unwrapAttributedRepr(entry.getTypeRepr());
1792+
if (isModuleQualified(repr, proto->getParentModule())) {
1793+
protocolsWithRetroactiveAttr.insert(proto);
1794+
}
1795+
1796+
protos.push_back(proto);
1797+
} else if (auto *pct = inheritedTy->getAs<ProtocolCompositionType>()) {
1798+
for (auto member : pct->getMembers()) {
1799+
collectProtocolsFromInheritedEntry(entry, member,
1800+
protocolsWithRetroactiveAttr, protos);
1801+
}
1802+
} else if (auto *ppt = inheritedTy->getAs<ParameterizedProtocolType>()) {
1803+
protos.push_back(ppt->getProtocol());
1804+
}
1805+
}
1806+
17801807
/// Determines if this extension declares a conformance of a type declared
17811808
/// outside this module to a protocol declared outside this module (but only
17821809
/// in library evolution mode)
@@ -1813,7 +1840,7 @@ static void diagnoseRetroactiveConformances(
18131840
// At this point, we know we're extending a type declared outside this module.
18141841
// We better only be conforming it to protocols declared within this module.
18151842
llvm::SmallMapVector<ProtocolDecl *, bool, 8> protocols;
1816-
llvm::SmallSet<ProtocolDecl *, 8> protocolsWithRetroactiveAttr;
1843+
llvm::SmallPtrSet<ProtocolDecl *, 2> protocolsWithRetroactiveAttr;
18171844

18181845
for (auto *conformance : ext->getLocalConformances()) {
18191846
auto *proto = conformance->getProtocol();
@@ -1841,27 +1868,8 @@ static void diagnoseRetroactiveConformances(
18411868
}
18421869

18431870
SmallVector<ProtocolDecl *, 2> protos;
1844-
if (auto *protoTy = inheritedTy->getAs<ProtocolType>()) {
1845-
auto *proto = protoTy->getDecl();
1846-
1847-
// As a fallback, to support previous language versions, also allow
1848-
// this through if the protocol has been explicitly module-qualified.
1849-
TypeRepr *repr = unwrapAttributedRepr(entry.getTypeRepr());
1850-
if (isModuleQualified(repr, proto->getParentModule())) {
1851-
protocolsWithRetroactiveAttr.insert(proto);
1852-
continue;
1853-
}
1854-
1855-
protos.push_back(proto);
1856-
} else if (auto *compositionTy = inheritedTy->getAs<ProtocolCompositionType>()) {
1857-
for (auto memberTy : compositionTy->getMembers()) {
1858-
if (auto *protoTy = memberTy->getAs<ProtocolType>()) {
1859-
protos.push_back(protoTy->getDecl());
1860-
}
1861-
}
1862-
} else {
1863-
continue;
1864-
}
1871+
collectProtocolsFromInheritedEntry(entry, inheritedTy,
1872+
protocolsWithRetroactiveAttr, protos);
18651873

18661874
for (auto *proto : protos) {
18671875
proto->walkInheritedProtocols([&](ProtocolDecl *decl) {

test/Sema/extension_retroactive_conformances.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ public protocol SampleProtocol2 {}
99
public protocol SampleProtocol1a: SampleProtocol1 {}
1010
public protocol SampleProtocol1b: SampleProtocol1 {}
1111

12+
public protocol SampleProtocol3<A> {
13+
associatedtype A
14+
}
15+
1216
public struct Sample1 {}
1317
public struct Sample2 {}
1418
public struct Sample2a {}
@@ -27,6 +31,9 @@ public struct SampleAlreadyConforms: SampleProtocol1 {}
2731

2832
public struct GenericSample1<T> {}
2933

34+
public struct Sample9 {}
35+
public struct Sample10 {}
36+
3037
#else
3138

3239
import Library
@@ -118,4 +125,10 @@ extension Sample7: SampleProtocol1 & SampleProtocol2 {}
118125

119126
extension Sample8: @retroactive SampleProtocol1 & SampleProtocol2 {} // ok
120127

128+
extension Sample9: SampleProtocol3<Int> {}
129+
// expected-warning@-1 {{extension declares a conformance of imported type 'Sample9' to imported protocol 'SampleProtocol3'; this will not behave correctly if the owners of 'Library' introduce this conformance in the future}}
130+
// expected-note@-2 {{add '@retroactive' to silence this warning}}
131+
132+
extension Sample10: @retroactive SampleProtocol3<Int> {}
133+
121134
#endif

0 commit comments

Comments
 (0)