Skip to content

Commit 86c26a9

Browse files
authored
Merge pull request #17993 from slavapestov/preserve-specialized-conformance-better
Preserve specialized conformance better
2 parents 6930a04 + 42a3ad3 commit 86c26a9

File tree

4 files changed

+73
-46
lines changed

4 files changed

+73
-46
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
}

lib/AST/Type.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2942,7 +2942,8 @@ Optional<ProtocolConformanceRef>
29422942
MakeAbstractConformanceForGenericType::operator()(CanType dependentType,
29432943
Type conformingReplacementType,
29442944
ProtocolDecl *conformedProtocol) const {
2945-
assert((conformingReplacementType->is<SubstitutableType>()
2945+
assert((conformingReplacementType->is<ErrorType>()
2946+
|| conformingReplacementType->is<SubstitutableType>()
29462947
|| conformingReplacementType->is<DependentMemberType>())
29472948
&& "replacement requires looking up a concrete conformance");
29482949
return ProtocolConformanceRef(conformedProtocol);

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 13 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3318,57 +3318,36 @@ void ConformanceChecker::ensureRequirementsAreSatisfied(
33183318
= Conformance->populateSignatureConformances();
33193319

33203320
class GatherConformancesListener : public GenericRequirementsCheckListener {
3321-
TypeChecker &tc;
33223321
NormalProtocolConformance *conformance;
33233322
std::function<void(ProtocolConformanceRef)> &writer;
33243323
public:
33253324
GatherConformancesListener(
3326-
TypeChecker &tc,
3327-
NormalProtocolConformance *conformance,
3328-
std::function<void(ProtocolConformanceRef)> &writer)
3329-
: tc(tc), conformance(conformance), writer(writer) { }
3325+
NormalProtocolConformance *conformance,
3326+
std::function<void(ProtocolConformanceRef)> &writer)
3327+
: conformance(conformance), writer(writer) { }
33303328

33313329
void satisfiedConformance(Type depTy, Type replacementTy,
33323330
ProtocolConformanceRef conformance) override {
33333331
// The conformance will use contextual types, but we want the
33343332
// interface type equivalent.
3335-
3336-
// If we have an inherited conformance for an archetype, dig out the
3337-
// superclass conformance to translate.
3338-
Type inheritedInterfaceType;
33393333
if (conformance.isConcrete() &&
33403334
conformance.getConcrete()->getType()->hasArchetype()) {
33413335
auto concreteConformance = conformance.getConcrete();
3342-
if (concreteConformance->getKind()
3343-
== ProtocolConformanceKind::Inherited &&
3344-
conformance.getConcrete()->getType()->is<ArchetypeType>()) {
3345-
inheritedInterfaceType =
3346-
concreteConformance->getType()->mapTypeOutOfContext();
3347-
concreteConformance =
3348-
cast<InheritedProtocolConformance>(concreteConformance)
3349-
->getInheritedConformance();
3350-
}
33513336

33523337
// Map the conformance.
3353-
// FIXME: It would be so much easier and efficient if we had
3354-
// ProtocolConformance::mapTypesOutOfContext().
33553338
auto interfaceType =
33563339
concreteConformance->getType()->mapTypeOutOfContext();
33573340

3358-
conformance = *tc.conformsToProtocol(
3359-
interfaceType,
3360-
conformance.getRequirement(),
3361-
this->conformance->getDeclContext(),
3362-
(ConformanceCheckFlags::SuppressDependencyTracking|
3363-
ConformanceCheckFlags::SkipConditionalRequirements));
3341+
concreteConformance = concreteConformance->subst(
3342+
interfaceType,
3343+
[](SubstitutableType *type) -> Type {
3344+
if (auto *archetypeType = type->getAs<ArchetypeType>())
3345+
return archetypeType->getInterfaceType();
3346+
return type;
3347+
},
3348+
MakeAbstractConformanceForGenericType());
33643349

3365-
// Reinstate inherited conformance.
3366-
if (inheritedInterfaceType) {
3367-
conformance =
3368-
ProtocolConformanceRef(
3369-
tc.Context.getInheritedConformance(inheritedInterfaceType,
3370-
conformance.getConcrete()));
3371-
}
3350+
conformance = ProtocolConformanceRef(concreteConformance);
33723351
}
33733352

33743353
writer(conformance);
@@ -3384,7 +3363,7 @@ void ConformanceChecker::ensureRequirementsAreSatisfied(
33843363

33853364
return false;
33863365
}
3387-
} listener(TC, Conformance, writer);
3366+
} listener(Conformance, writer);
33883367

33893368
auto result = TC.checkGenericArguments(
33903369
DC, Loc, Loc,
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)