Skip to content

Commit 42a3ad3

Browse files
committed
AST: Fix over-eager collapseSpecializedConformance()
It's possible that the conforming type is equal to the generic conformance type, but some of the substitutions replace an abstract conformance with a concrete one. In this case we cannot collapse away the specialized conformance, because we lose information that way. Fixes <rdar://problem/40164371>.
1 parent f242a23 commit 42a3ad3

File tree

2 files changed

+58
-11
lines changed

2 files changed

+58
-11
lines changed

lib/AST/ASTContext.cpp

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1784,24 +1784,26 @@ ASTContext::getConformance(Type conformingType,
17841784
/// that instead.
17851785
static ProtocolConformance *collapseSpecializedConformance(
17861786
Type type,
1787-
ProtocolConformance *conformance) {
1787+
ProtocolConformance *conformance,
1788+
SubstitutionMap substitutions) {
17881789
while (true) {
1789-
// If the conformance matches, return it.
1790-
if (conformance->getType()->isEqual(type))
1791-
return conformance;
1792-
17931790
switch (conformance->getKind()) {
1794-
case ProtocolConformanceKind::Inherited:
1795-
conformance = cast<InheritedProtocolConformance>(conformance)
1796-
->getInheritedConformance();
1797-
break;
1798-
17991791
case ProtocolConformanceKind::Specialized:
18001792
conformance = cast<SpecializedProtocolConformance>(conformance)
18011793
->getGenericConformance();
18021794
break;
18031795

18041796
case ProtocolConformanceKind::Normal:
1797+
case ProtocolConformanceKind::Inherited:
1798+
// If the conformance matches, return it.
1799+
if (conformance->getType()->isEqual(type)) {
1800+
for (auto subConformance : substitutions.getConformances())
1801+
if (!subConformance.isAbstract())
1802+
return nullptr;
1803+
1804+
return conformance;
1805+
}
1806+
18051807
return nullptr;
18061808
}
18071809
}
@@ -1814,7 +1816,8 @@ ASTContext::getSpecializedConformance(Type type,
18141816
// If we are performing a substitution that would get us back to the
18151817
// a prior conformance (e.g., mapping into and then out of a conformance),
18161818
// return the existing conformance.
1817-
if (auto existing = collapseSpecializedConformance(type, generic)) {
1819+
if (auto existing = collapseSpecializedConformance(type, generic,
1820+
substitutions)) {
18181821
++NumCollapsedSpecializedProtocolConformances;
18191822
return existing;
18201823
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// RUN: %target-swift-frontend -emit-sil %s
2+
3+
protocol X1 {
4+
associatedtype X3 : X4
5+
}
6+
7+
protocol X4 {
8+
associatedtype X15
9+
}
10+
11+
protocol X7 { }
12+
13+
protocol X9 : X7 {
14+
associatedtype X10 : X7
15+
}
16+
17+
struct X12 : X9 {
18+
typealias X10 = X12
19+
}
20+
21+
struct X13<I1 : X7> : X9 {
22+
typealias X10 = X13<I1>
23+
}
24+
25+
struct X14<G : X4> : X4 where G.X15 : X9 {
26+
typealias X15 = X13<G.X15.X10>
27+
}
28+
29+
struct X17<A : X4> : X1 where A.X15 == X12 {
30+
typealias X3 = X14<A>
31+
}
32+
33+
struct X18 : X4 {
34+
typealias X15 = X12
35+
}
36+
37+
@_transparent
38+
func callee<T>(_: T) where T : X1 {
39+
let _: T.X3.X15? = nil
40+
}
41+
42+
func caller(b: X17<X18>) {
43+
callee(b)
44+
}

0 commit comments

Comments
 (0)