Skip to content

Commit 5159576

Browse files
authored
Merge pull request #18018 from slavapestov/preserve-specialized-conformance-better-4.2
Preserve specialized conformance better [4.2]
2 parents cd76549 + c81f84e commit 5159576

File tree

5 files changed

+106
-45
lines changed

5 files changed

+106
-45
lines changed

include/swift/AST/SubstitutionMap.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,9 @@ class SubstitutionMap {
181181
/// Profile the substitution map, for use with LLVM's FoldingSet.
182182
void profile(llvm::FoldingSetNodeID &id) const;
183183

184+
const llvm::DenseMap<CanType, SmallVector<ProtocolConformanceRef, 1>> &
185+
getConformanceMap() const { return conformanceMap; }
186+
184187
private:
185188
friend class GenericSignature;
186189
friend class GenericEnvironment;

lib/AST/ASTContext.cpp

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1816,24 +1816,57 @@ ASTContext::getConformance(Type conformingType,
18161816
/// that instead.
18171817
static ProtocolConformance *collapseSpecializedConformance(
18181818
Type type,
1819-
ProtocolConformance *conformance) {
1819+
ProtocolConformance *conformance,
1820+
SubstitutionList substitutions) {
18201821
while (true) {
1821-
// If the conformance matches, return it.
1822-
if (conformance->getType()->isEqual(type))
1823-
return conformance;
1824-
18251822
switch (conformance->getKind()) {
1826-
case ProtocolConformanceKind::Inherited:
1827-
conformance = cast<InheritedProtocolConformance>(conformance)
1828-
->getInheritedConformance();
1823+
case ProtocolConformanceKind::Specialized:
1824+
conformance = cast<SpecializedProtocolConformance>(conformance)
1825+
->getGenericConformance();
18291826
break;
18301827

1828+
case ProtocolConformanceKind::Normal:
1829+
case ProtocolConformanceKind::Inherited:
1830+
// If the conformance matches, return it.
1831+
if (conformance->getType()->isEqual(type)) {
1832+
for (auto substitution : substitutions)
1833+
for (auto subConformance : substitution.getConformances())
1834+
if (!subConformance.isAbstract())
1835+
return nullptr;
1836+
1837+
return conformance;
1838+
}
1839+
1840+
return nullptr;
1841+
}
1842+
}
1843+
}
1844+
1845+
/// If one of the ancestor conformances already has a matching type, use
1846+
/// that instead.
1847+
static ProtocolConformance *collapseSpecializedConformance(
1848+
Type type,
1849+
ProtocolConformance *conformance,
1850+
const SubstitutionMap &substitutions) {
1851+
while (true) {
1852+
switch (conformance->getKind()) {
18311853
case ProtocolConformanceKind::Specialized:
18321854
conformance = cast<SpecializedProtocolConformance>(conformance)
18331855
->getGenericConformance();
18341856
break;
18351857

18361858
case ProtocolConformanceKind::Normal:
1859+
case ProtocolConformanceKind::Inherited:
1860+
// If the conformance matches, return it.
1861+
if (conformance->getType()->isEqual(type)) {
1862+
for (auto conformances : substitutions.getConformanceMap())
1863+
for (auto subConformance : conformances.second)
1864+
if (!subConformance.isAbstract())
1865+
return nullptr;
1866+
1867+
return conformance;
1868+
}
1869+
18371870
return nullptr;
18381871
}
18391872
}
@@ -1848,7 +1881,8 @@ ASTContext::getSpecializedConformance(Type type,
18481881
// a prior conformance (e.g., mapping into and then out of a conformance),
18491882
// return the existing conformance.
18501883
if (!alreadyCheckedCollapsed) {
1851-
if (auto existing = collapseSpecializedConformance(type, generic)) {
1884+
if (auto existing = collapseSpecializedConformance(type, generic,
1885+
substitutions)) {
18521886
++NumCollapsedSpecializedProtocolConformances;
18531887
return existing;
18541888
}
@@ -1885,7 +1919,7 @@ ASTContext::getSpecializedConformance(Type type,
18851919
// If we are performing a substitution that would get us back to the
18861920
// a prior conformance (e.g., mapping into and then out of a conformance),
18871921
// return the existing conformance.
1888-
if (auto existing = collapseSpecializedConformance(type, generic)) {
1922+
if (auto existing = collapseSpecializedConformance(type, generic, subMap)) {
18891923
++NumCollapsedSpecializedProtocolConformances;
18901924
return existing;
18911925
}

lib/AST/Type.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2920,7 +2920,8 @@ Optional<ProtocolConformanceRef>
29202920
MakeAbstractConformanceForGenericType::operator()(CanType dependentType,
29212921
Type conformingReplacementType,
29222922
ProtocolType *conformedProtocol) const {
2923-
assert((conformingReplacementType->is<SubstitutableType>()
2923+
assert((conformingReplacementType->is<ErrorType>()
2924+
|| conformingReplacementType->is<SubstitutableType>()
29242925
|| conformingReplacementType->is<DependentMemberType>())
29252926
&& "replacement requires looking up a concrete conformance");
29262927
return ProtocolConformanceRef(conformedProtocol->getDecl());

lib/Sema/TypeCheckProtocol.cpp

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

32923292
class GatherConformancesListener : public GenericRequirementsCheckListener {
3293-
TypeChecker &tc;
32943293
NormalProtocolConformance *conformance;
32953294
std::function<void(ProtocolConformanceRef)> &writer;
32963295
public:
32973296
GatherConformancesListener(
3298-
TypeChecker &tc,
3299-
NormalProtocolConformance *conformance,
3300-
std::function<void(ProtocolConformanceRef)> &writer)
3301-
: tc(tc), conformance(conformance), writer(writer) { }
3297+
NormalProtocolConformance *conformance,
3298+
std::function<void(ProtocolConformanceRef)> &writer)
3299+
: conformance(conformance), writer(writer) { }
33023300

33033301
void satisfiedConformance(Type depTy, Type replacementTy,
33043302
ProtocolConformanceRef conformance) override {
33053303
// The conformance will use contextual types, but we want the
33063304
// interface type equivalent.
3307-
3308-
// If we have an inherited conformance for an archetype, dig out the
3309-
// superclass conformance to translate.
3310-
Type inheritedInterfaceType;
33113305
if (conformance.isConcrete() &&
33123306
conformance.getConcrete()->getType()->hasArchetype()) {
33133307
auto concreteConformance = conformance.getConcrete();
3314-
if (concreteConformance->getKind()
3315-
== ProtocolConformanceKind::Inherited &&
3316-
conformance.getConcrete()->getType()->is<ArchetypeType>()) {
3317-
inheritedInterfaceType =
3318-
concreteConformance->getType()->mapTypeOutOfContext();
3319-
concreteConformance =
3320-
cast<InheritedProtocolConformance>(concreteConformance)
3321-
->getInheritedConformance();
3322-
}
33233308

33243309
// Map the conformance.
3325-
// FIXME: It would be so much easier and efficient if we had
3326-
// ProtocolConformance::mapTypesOutOfContext().
33273310
auto interfaceType =
33283311
concreteConformance->getType()->mapTypeOutOfContext();
33293312

3330-
conformance = *tc.conformsToProtocol(
3331-
interfaceType,
3332-
conformance.getRequirement(),
3333-
this->conformance->getDeclContext(),
3334-
(ConformanceCheckFlags::SuppressDependencyTracking|
3335-
ConformanceCheckFlags::SkipConditionalRequirements));
3313+
concreteConformance = concreteConformance->subst(
3314+
interfaceType,
3315+
[](SubstitutableType *type) -> Type {
3316+
if (auto *archetypeType = type->getAs<ArchetypeType>())
3317+
return archetypeType->getInterfaceType();
3318+
return type;
3319+
},
3320+
MakeAbstractConformanceForGenericType());
33363321

3337-
// Reinstate inherited conformance.
3338-
if (inheritedInterfaceType) {
3339-
conformance =
3340-
ProtocolConformanceRef(
3341-
tc.Context.getInheritedConformance(inheritedInterfaceType,
3342-
conformance.getConcrete()));
3343-
}
3322+
conformance = ProtocolConformanceRef(concreteConformance);
33443323
}
33453324

33463325
writer(conformance);
@@ -3356,7 +3335,7 @@ void ConformanceChecker::ensureRequirementsAreSatisfied(
33563335

33573336
return false;
33583337
}
3359-
} listener(TC, Conformance, writer);
3338+
} listener(Conformance, writer);
33603339

33613340
auto result = TC.checkGenericArguments(
33623341
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)