Skip to content

Commit 182946e

Browse files
authored
Merge pull request swiftlang#60370 from slavapestov/cleaner-conformance-collapse
Cleaner conformance collapsing
2 parents 2944374 + 1d8b0f2 commit 182946e

13 files changed

+76
-117
lines changed

include/swift/AST/ASTContext.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ namespace swift {
105105
class NormalProtocolConformance;
106106
class OpaqueTypeDecl;
107107
class InheritedProtocolConformance;
108+
class RootProtocolConformance;
108109
class SelfProtocolConformance;
109110
class SpecializedProtocolConformance;
110111
enum class BuiltinConformanceKind;
@@ -1245,7 +1246,7 @@ class ASTContext final {
12451246
/// specialized conformance from the generic conformance.
12461247
ProtocolConformance *
12471248
getSpecializedConformance(Type type,
1248-
ProtocolConformance *generic,
1249+
RootProtocolConformance *generic,
12491250
SubstitutionMap substitutions);
12501251

12511252
/// Produce an inherited conformance, for subclasses of a type

include/swift/AST/ProtocolConformance.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -753,7 +753,7 @@ class SelfProtocolConformance : public RootProtocolConformance {
753753
class SpecializedProtocolConformance : public ProtocolConformance,
754754
public llvm::FoldingSetNode {
755755
/// The generic conformance from which this conformance was derived.
756-
ProtocolConformance *GenericConformance;
756+
RootProtocolConformance *GenericConformance;
757757

758758
/// The substitutions applied to the generic conformance to produce this
759759
/// conformance.
@@ -772,15 +772,15 @@ class SpecializedProtocolConformance : public ProtocolConformance,
772772
friend class ASTContext;
773773

774774
SpecializedProtocolConformance(Type conformingType,
775-
ProtocolConformance *genericConformance,
775+
RootProtocolConformance *genericConformance,
776776
SubstitutionMap substitutions);
777777

778778
void computeConditionalRequirements() const;
779779

780780
public:
781781
/// Get the generic conformance from which this conformance was derived,
782782
/// if there is one.
783-
ProtocolConformance *getGenericConformance() const {
783+
RootProtocolConformance *getGenericConformance() const {
784784
return GenericConformance;
785785
}
786786

@@ -866,7 +866,7 @@ class SpecializedProtocolConformance : public ProtocolConformance,
866866
}
867867

868868
static void Profile(llvm::FoldingSetNodeID &ID, Type type,
869-
ProtocolConformance *genericConformance,
869+
RootProtocolConformance *genericConformance,
870870
SubstitutionMap subs) {
871871
ID.AddPointer(type.getPointer());
872872
ID.AddPointer(genericConformance);

include/swift/AST/RequirementEnvironment.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222

2323
namespace swift {
2424

25+
class RootProtocolConformance;
26+
2527
/// Describes the environment of a requirement that will be used when
2628
/// matching witnesses against the requirement and to form the resulting
2729
/// \c Witness value.
@@ -99,7 +101,7 @@ class RequirementEnvironment {
99101
GenericSignature reqSig,
100102
ProtocolDecl *proto,
101103
ClassDecl *covariantSelf,
102-
ProtocolConformance *conformance);
104+
RootProtocolConformance *conformance);
103105

104106
/// Retrieve the generic signature of the requirement.
105107
GenericSignature getRequirementSignature() const {

lib/AST/ASTContext.cpp

Lines changed: 22 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2387,48 +2387,28 @@ ASTContext::getBuiltinConformance(
23872387
return entry;
23882388
}
23892389

2390-
/// If one of the ancestor conformances already has a matching type, use
2391-
/// that instead.
2392-
static ProtocolConformance *collapseSpecializedConformance(
2393-
Type type,
2394-
ProtocolConformance *conformance,
2395-
SubstitutionMap substitutions) {
2396-
while (true) {
2397-
switch (conformance->getKind()) {
2398-
case ProtocolConformanceKind::Specialized:
2399-
conformance = cast<SpecializedProtocolConformance>(conformance)
2400-
->getGenericConformance();
2401-
break;
2402-
2403-
case ProtocolConformanceKind::Normal:
2404-
case ProtocolConformanceKind::Inherited:
2405-
case ProtocolConformanceKind::Self:
2406-
case ProtocolConformanceKind::Builtin:
2407-
// If the conformance matches, return it.
2408-
if (conformance->getType()->isEqual(type)) {
2409-
for (auto subConformance : substitutions.getConformances())
2410-
if (!subConformance.isAbstract())
2411-
return nullptr;
2412-
2413-
return conformance;
2414-
}
2390+
static bool collapseSpecializedConformance(Type type,
2391+
RootProtocolConformance *conformance,
2392+
SubstitutionMap substitutions) {
2393+
if (!conformance->getType()->isEqual(type))
2394+
return false;
24152395

2416-
return nullptr;
2417-
}
2396+
for (auto subConformance : substitutions.getConformances()) {
2397+
if (!subConformance.isAbstract())
2398+
return false;
24182399
}
2400+
2401+
return true;
24192402
}
24202403

24212404
ProtocolConformance *
24222405
ASTContext::getSpecializedConformance(Type type,
2423-
ProtocolConformance *generic,
2406+
RootProtocolConformance *generic,
24242407
SubstitutionMap substitutions) {
2425-
// If we are performing a substitution that would get us back to the
2426-
// a prior conformance (e.g., mapping into and then out of a conformance),
2427-
// return the existing conformance.
2428-
if (auto existing = collapseSpecializedConformance(type, generic,
2429-
substitutions)) {
2408+
// If the specialization is a no-op, use the root conformance instead.
2409+
if (collapseSpecializedConformance(type, generic, substitutions)) {
24302410
++NumCollapsedSpecializedProtocolConformances;
2431-
return existing;
2411+
return generic;
24322412
}
24332413

24342414
llvm::FoldingSetNodeID id;
@@ -2456,6 +2436,14 @@ ASTContext::getSpecializedConformance(Type type,
24562436

24572437
InheritedProtocolConformance *
24582438
ASTContext::getInheritedConformance(Type type, ProtocolConformance *inherited) {
2439+
// Collapse multiple levels of inherited conformance.
2440+
while (auto *otherInherited = dyn_cast<InheritedProtocolConformance>(inherited))
2441+
inherited = otherInherited->getInheritedConformance();
2442+
2443+
assert(isa<SpecializedProtocolConformance>(inherited) ||
2444+
isa<NormalProtocolConformance>(inherited) ||
2445+
isa<BuiltinProtocolConformance>(inherited));
2446+
24592447
llvm::FoldingSetNodeID id;
24602448
InheritedProtocolConformance::Profile(id, type, inherited);
24612449

lib/AST/Module.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1447,7 +1447,8 @@ LookupConformanceInModuleRequest::evaluate(
14471447
auto subMap = type->getContextSubstitutionMap(mod, explicitConformanceDC);
14481448

14491449
// Create the specialized conformance entry.
1450-
auto result = ctx.getSpecializedConformance(type, conformance, subMap);
1450+
auto result = ctx.getSpecializedConformance(type,
1451+
cast<RootProtocolConformance>(conformance), subMap);
14511452
return ProtocolConformanceRef(result);
14521453
}
14531454
}

lib/AST/ProtocolConformance.cpp

Lines changed: 22 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -347,46 +347,19 @@ GenericSignature ProtocolConformance::getGenericSignature() const {
347347
}
348348

349349
SubstitutionMap ProtocolConformance::getSubstitutions(ModuleDecl *M) const {
350-
// Walk down to the base NormalProtocolConformance.
351-
SubstitutionMap subMap;
352-
const ProtocolConformance *parent = this;
353-
while (!isa<RootProtocolConformance>(parent)) {
354-
switch (parent->getKind()) {
355-
case ProtocolConformanceKind::Normal:
356-
case ProtocolConformanceKind::Self:
357-
case ProtocolConformanceKind::Builtin:
358-
llvm_unreachable("should have exited the loop?!");
359-
case ProtocolConformanceKind::Inherited:
360-
parent =
361-
cast<InheritedProtocolConformance>(parent)->getInheritedConformance();
362-
break;
363-
case ProtocolConformanceKind::Specialized: {
364-
auto SC = cast<SpecializedProtocolConformance>(parent);
365-
parent = SC->getGenericConformance();
366-
assert(subMap.empty() && "multiple conformance specializations?!");
367-
subMap = SC->getSubstitutionMap();
368-
break;
369-
}
370-
}
371-
}
350+
const ProtocolConformance *conformance = this;
372351

373-
// Found something; we're done!
374-
if (!subMap.empty())
375-
return subMap;
352+
if (auto *inheritedC = dyn_cast<InheritedProtocolConformance>(conformance))
353+
conformance = inheritedC->getInheritedConformance();
376354

377-
// If the normal conformance is for a generic type, and we didn't hit a
378-
// specialized conformance, collect the substitutions from the generic type.
379-
// FIXME: The AST should do this for us.
380-
const NormalProtocolConformance *normalC =
381-
dyn_cast<NormalProtocolConformance>(parent);
382-
if (!normalC)
383-
return SubstitutionMap();
355+
if (auto *specializedC = dyn_cast<SpecializedProtocolConformance>(conformance))
356+
return specializedC->getSubstitutionMap();
384357

385-
if (!normalC->getType()->isSpecialized())
386-
return SubstitutionMap();
358+
auto *rootC = cast<RootProtocolConformance>(conformance);
359+
if (auto genericSig = rootC->getGenericSignature())
360+
return genericSig->getIdentitySubstitutionMap();
387361

388-
auto *DC = normalC->getDeclContext();
389-
return normalC->getType()->getContextSubstitutionMap(M, DC);
362+
return SubstitutionMap();
390363
}
391364

392365
bool RootProtocolConformance::isInvalid() const {
@@ -957,14 +930,11 @@ void NormalProtocolConformance::overrideWitness(ValueDecl *requirement,
957930

958931
SpecializedProtocolConformance::SpecializedProtocolConformance(
959932
Type conformingType,
960-
ProtocolConformance *genericConformance,
933+
RootProtocolConformance *genericConformance,
961934
SubstitutionMap substitutions)
962935
: ProtocolConformance(ProtocolConformanceKind::Specialized, conformingType),
963936
GenericConformance(genericConformance),
964-
GenericSubstitutions(substitutions)
965-
{
966-
assert(genericConformance->getKind() != ProtocolConformanceKind::Specialized);
967-
}
937+
GenericSubstitutions(substitutions) {}
968938

969939
void SpecializedProtocolConformance::computeConditionalRequirements() const {
970940
// already computed?
@@ -1133,22 +1103,12 @@ ProtocolConformance::getRootNormalConformance() const {
11331103
const RootProtocolConformance *
11341104
ProtocolConformance::getRootConformance() const {
11351105
const ProtocolConformance *C = this;
1136-
while (true) {
1137-
switch (C->getKind()) {
1138-
case ProtocolConformanceKind::Normal:
1139-
case ProtocolConformanceKind::Self:
1140-
case ProtocolConformanceKind::Builtin:
1141-
return cast<RootProtocolConformance>(C);
1142-
case ProtocolConformanceKind::Inherited:
1143-
C = cast<InheritedProtocolConformance>(C)
1144-
->getInheritedConformance();
1145-
break;
1146-
case ProtocolConformanceKind::Specialized:
1147-
C = cast<SpecializedProtocolConformance>(C)
1148-
->getGenericConformance();
1149-
break;
1150-
}
1151-
}
1106+
if (auto *inheritedC = dyn_cast<InheritedProtocolConformance>(C))
1107+
C = inheritedC->getInheritedConformance();
1108+
if (auto *specializedC = dyn_cast<SpecializedProtocolConformance>(C))
1109+
return specializedC->getGenericConformance();
1110+
1111+
return cast<RootProtocolConformance>(C);
11521112
}
11531113

11541114
bool ProtocolConformance::isVisibleFrom(const DeclContext *dc) const {
@@ -1181,9 +1141,11 @@ ProtocolConformance::subst(TypeSubstitutionFn subs,
11811141

11821142
auto subMap = SubstitutionMap::get(getGenericSignature(),
11831143
subs, conformances);
1144+
1145+
auto *mutableThis = const_cast<ProtocolConformance *>(this);
11841146
return substType->getASTContext()
11851147
.getSpecializedConformance(substType,
1186-
const_cast<ProtocolConformance *>(this),
1148+
cast<NormalProtocolConformance>(mutableThis),
11871149
subMap);
11881150
}
11891151
case ProtocolConformanceKind::Builtin: {
@@ -1660,7 +1622,8 @@ ProtocolConformance *ProtocolConformance::getCanonicalConformance() {
16601622
auto genericConformance = spec->getGenericConformance();
16611623
return Ctx.getSpecializedConformance(
16621624
getType()->getCanonicalType(),
1663-
genericConformance->getCanonicalConformance(),
1625+
cast<RootProtocolConformance>(
1626+
genericConformance->getCanonicalConformance()),
16641627
spec->getSubstitutionMap().getCanonical());
16651628
}
16661629
}

lib/AST/RequirementEnvironment.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ RequirementEnvironment::RequirementEnvironment(
3636
GenericSignature reqSig,
3737
ProtocolDecl *proto,
3838
ClassDecl *covariantSelf,
39-
ProtocolConformance *conformance)
39+
RootProtocolConformance *conformance)
4040
: reqSig(reqSig) {
4141
ASTContext &ctx = conformanceDC->getASTContext();
4242

lib/AST/Type.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3134,7 +3134,8 @@ getForeignRepresentable(Type type, ForeignLanguage language,
31343134
if (result.getKind() == ForeignRepresentableKind::Bridged
31353135
&& !result.getConformance()->getType()->isEqual(type)) {
31363136
auto specialized = type->getASTContext()
3137-
.getSpecializedConformance(type, result.getConformance(),
3137+
.getSpecializedConformance(type,
3138+
cast<RootProtocolConformance>(result.getConformance()),
31383139
boundGenericType->getContextSubstitutionMap(dc->getParentModule(),
31393140
boundGenericType->getDecl()));
31403141
result = ForeignRepresentationInfo::forBridged(specialized);

lib/SIL/Parser/ParseSIL.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7089,8 +7089,10 @@ ProtocolConformanceRef SILParser::parseProtocolConformanceHelper(
70897089
if (!subMap)
70907090
return ProtocolConformanceRef();
70917091

7092+
auto *rootConform = cast<RootProtocolConformance>(
7093+
genericConform.getConcrete());
70927094
auto result = P.Context.getSpecializedConformance(
7093-
ConformingTy, genericConform.getConcrete(), subMap);
7095+
ConformingTy, rootConform, subMap);
70947096
return ProtocolConformanceRef(result);
70957097
}
70967098

lib/SILGen/SILGenLazyConformance.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,17 +37,18 @@ void SILGenModule::useConformance(ProtocolConformanceRef conformanceRef) {
3737
if (auto *inherited = dyn_cast<InheritedProtocolConformance>(conformance))
3838
conformance = inherited->getInheritedConformance();
3939

40+
// Emit any conformances implied by conditional requirements.
41+
if (auto *specialized = dyn_cast<SpecializedProtocolConformance>(conformance)) {
42+
useConformancesFromSubstitutions(specialized->getSubstitutionMap());
43+
conformance = specialized->getGenericConformance();
44+
}
45+
4046
// Get the normal conformance. If we don't have one, this is a self
4147
// conformance, which we can ignore.
42-
auto normal = dyn_cast<NormalProtocolConformance>(
43-
conformance->getRootConformance());
48+
auto normal = dyn_cast<NormalProtocolConformance>(conformance);
4449
if (normal == nullptr)
4550
return;
4651

47-
// Emit any conformances implied by conditional requirements.
48-
if (auto *specialized = dyn_cast<SpecializedProtocolConformance>(conformance))
49-
useConformancesFromSubstitutions(specialized->getSubstitutionMap());
50-
5152
// If this conformance was not synthesized by the ClangImporter, we're not
5253
// going to be emitting it lazily either, so we can avoid doing anything
5354
// below.

0 commit comments

Comments
 (0)