Skip to content

Commit cd2b558

Browse files
committed
Fix a bug with inlining self-conformances.
1 parent 5c205b4 commit cd2b558

File tree

3 files changed

+65
-53
lines changed

3 files changed

+65
-53
lines changed

include/swift/AST/Module.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,11 @@ class ModuleDecl : public DeclContext, public TypeDecl {
385385
Optional<ProtocolConformanceRef>
386386
lookupConformance(Type type, ProtocolDecl *protocol);
387387

388+
/// Look for the conformance of the given existential type to the given
389+
/// protocol.
390+
Optional<ProtocolConformanceRef>
391+
lookupExistentialConformance(Type type, ProtocolDecl *protocol);
392+
388393
/// Find a member named \p name in \p container that was declared in this
389394
/// module.
390395
///

lib/AST/Module.cpp

Lines changed: 53 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,57 @@ void ModuleDecl::getDisplayDecls(SmallVectorImpl<Decl*> &Results) const {
570570
FORWARD(getDisplayDecls, (Results));
571571
}
572572

573+
Optional<ProtocolConformanceRef>
574+
ModuleDecl::lookupExistentialConformance(Type type, ProtocolDecl *protocol) {
575+
assert(type->isExistentialType());
576+
577+
// If the existential type cannot be represented or the protocol does not
578+
// conform to itself, there's no point in looking further.
579+
if (!protocol->existentialConformsToSelf())
580+
return None;
581+
582+
auto layout = type->getExistentialLayout();
583+
584+
// Due to an IRGen limitation, witness tables cannot be passed from an
585+
// existential to an archetype parameter, so for now we restrict this to
586+
// @objc protocols.
587+
if (!layout.isObjC()) {
588+
return None;
589+
}
590+
591+
// If the existential is class-constrained, the class might conform
592+
// concretely.
593+
if (auto superclass = layout.explicitSuperclass) {
594+
if (auto result = lookupConformance(superclass, protocol))
595+
return result;
596+
}
597+
598+
// Otherwise, the existential might conform abstractly.
599+
for (auto proto : layout.getProtocols()) {
600+
auto *protoDecl = proto->getDecl();
601+
602+
// If we found the protocol we're looking for, return an abstract
603+
// conformance to it.
604+
if (protoDecl == protocol)
605+
return ProtocolConformanceRef(protocol);
606+
607+
// If the protocol has a superclass constraint, we might conform
608+
// concretely.
609+
if (auto superclass = protoDecl->getSuperclass()) {
610+
if (auto result = lookupConformance(superclass, protocol))
611+
return result;
612+
}
613+
614+
// Now check refined protocols.
615+
if (protoDecl->inheritsFrom(protocol))
616+
return ProtocolConformanceRef(protocol);
617+
}
618+
619+
// We didn't find our protocol in the existential's list; it doesn't
620+
// conform.
621+
return None;
622+
}
623+
573624
Optional<ProtocolConformanceRef>
574625
ModuleDecl::lookupConformance(Type type, ProtocolDecl *protocol) {
575626
ASTContext &ctx = getASTContext();
@@ -609,52 +660,8 @@ ModuleDecl::lookupConformance(Type type, ProtocolDecl *protocol) {
609660
// An existential conforms to a protocol if the protocol is listed in the
610661
// existential's list of conformances and the existential conforms to
611662
// itself.
612-
if (type->isExistentialType()) {
613-
// If the existential type cannot be represented or the protocol does not
614-
// conform to itself, there's no point in looking further.
615-
if (!protocol->existentialConformsToSelf())
616-
return None;
617-
618-
auto layout = type->getExistentialLayout();
619-
620-
// Due to an IRGen limitation, witness tables cannot be passed from an
621-
// existential to an archetype parameter, so for now we restrict this to
622-
// @objc protocols.
623-
if (!layout.isObjC())
624-
return None;
625-
626-
// If the existential is class-constrained, the class might conform
627-
// concretely.
628-
if (auto superclass = layout.explicitSuperclass) {
629-
if (auto result = lookupConformance(superclass, protocol))
630-
return result;
631-
}
632-
633-
// Otherwise, the existential might conform abstractly.
634-
for (auto proto : layout.getProtocols()) {
635-
auto *protoDecl = proto->getDecl();
636-
637-
// If we found the protocol we're looking for, return an abstract
638-
// conformance to it.
639-
if (protoDecl == protocol)
640-
return ProtocolConformanceRef(protocol);
641-
642-
// If the protocol has a superclass constraint, we might conform
643-
// concretely.
644-
if (auto superclass = protoDecl->getSuperclass()) {
645-
if (auto result = lookupConformance(superclass, protocol))
646-
return result;
647-
}
648-
649-
// Now check refined protocols.
650-
if (protoDecl->inheritsFrom(protocol))
651-
return ProtocolConformanceRef(protocol);
652-
}
653-
654-
// We didn't find our protocol in the existential's list; it doesn't
655-
// conform.
656-
return None;
657-
}
663+
if (type->isExistentialType())
664+
return lookupExistentialConformance(type, protocol);
658665

659666
// Type variables have trivial conformances.
660667
if (type->isTypeVariableOrMember())

lib/AST/ProtocolConformance.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -112,12 +112,6 @@ ProtocolConformanceRef::subst(Type origType,
112112
if (substType->isOpenedExistential())
113113
return *this;
114114

115-
// If the substituted type is an existential, we have a self-conforming
116-
// existential being substituted in place of itself. There's no
117-
// conformance information in this case, so just return.
118-
if (substType->isObjCExistentialType())
119-
return *this;
120-
121115
auto *proto = getRequirement();
122116

123117
// Check the conformance map.
@@ -126,7 +120,13 @@ ProtocolConformanceRef::subst(Type origType,
126120
return *result;
127121
}
128122

129-
llvm_unreachable("Invalid conformance substitution");
123+
// The only remaining case is that the type is an existential that
124+
// self-conforms.
125+
assert(substType->isExistentialType());
126+
auto optConformance =
127+
proto->getModuleContext()->lookupExistentialConformance(substType, proto);
128+
assert(optConformance && "existential type didn't self-conform");
129+
return *optConformance;
130130
}
131131

132132
Type

0 commit comments

Comments
 (0)