mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Fix a bug with inlining self-conformances.
This commit is contained in:
@@ -385,6 +385,11 @@ public:
|
|||||||
Optional<ProtocolConformanceRef>
|
Optional<ProtocolConformanceRef>
|
||||||
lookupConformance(Type type, ProtocolDecl *protocol);
|
lookupConformance(Type type, ProtocolDecl *protocol);
|
||||||
|
|
||||||
|
/// Look for the conformance of the given existential type to the given
|
||||||
|
/// protocol.
|
||||||
|
Optional<ProtocolConformanceRef>
|
||||||
|
lookupExistentialConformance(Type type, ProtocolDecl *protocol);
|
||||||
|
|
||||||
/// Find a member named \p name in \p container that was declared in this
|
/// Find a member named \p name in \p container that was declared in this
|
||||||
/// module.
|
/// module.
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -570,6 +570,57 @@ void ModuleDecl::getDisplayDecls(SmallVectorImpl<Decl*> &Results) const {
|
|||||||
FORWARD(getDisplayDecls, (Results));
|
FORWARD(getDisplayDecls, (Results));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Optional<ProtocolConformanceRef>
|
||||||
|
ModuleDecl::lookupExistentialConformance(Type type, ProtocolDecl *protocol) {
|
||||||
|
assert(type->isExistentialType());
|
||||||
|
|
||||||
|
// If the existential type cannot be represented or the protocol does not
|
||||||
|
// conform to itself, there's no point in looking further.
|
||||||
|
if (!protocol->existentialConformsToSelf())
|
||||||
|
return None;
|
||||||
|
|
||||||
|
auto layout = type->getExistentialLayout();
|
||||||
|
|
||||||
|
// Due to an IRGen limitation, witness tables cannot be passed from an
|
||||||
|
// existential to an archetype parameter, so for now we restrict this to
|
||||||
|
// @objc protocols.
|
||||||
|
if (!layout.isObjC()) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the existential is class-constrained, the class might conform
|
||||||
|
// concretely.
|
||||||
|
if (auto superclass = layout.explicitSuperclass) {
|
||||||
|
if (auto result = lookupConformance(superclass, protocol))
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, the existential might conform abstractly.
|
||||||
|
for (auto proto : layout.getProtocols()) {
|
||||||
|
auto *protoDecl = proto->getDecl();
|
||||||
|
|
||||||
|
// If we found the protocol we're looking for, return an abstract
|
||||||
|
// conformance to it.
|
||||||
|
if (protoDecl == protocol)
|
||||||
|
return ProtocolConformanceRef(protocol);
|
||||||
|
|
||||||
|
// If the protocol has a superclass constraint, we might conform
|
||||||
|
// concretely.
|
||||||
|
if (auto superclass = protoDecl->getSuperclass()) {
|
||||||
|
if (auto result = lookupConformance(superclass, protocol))
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now check refined protocols.
|
||||||
|
if (protoDecl->inheritsFrom(protocol))
|
||||||
|
return ProtocolConformanceRef(protocol);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We didn't find our protocol in the existential's list; it doesn't
|
||||||
|
// conform.
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
Optional<ProtocolConformanceRef>
|
Optional<ProtocolConformanceRef>
|
||||||
ModuleDecl::lookupConformance(Type type, ProtocolDecl *protocol) {
|
ModuleDecl::lookupConformance(Type type, ProtocolDecl *protocol) {
|
||||||
ASTContext &ctx = getASTContext();
|
ASTContext &ctx = getASTContext();
|
||||||
@@ -609,52 +660,8 @@ ModuleDecl::lookupConformance(Type type, ProtocolDecl *protocol) {
|
|||||||
// An existential conforms to a protocol if the protocol is listed in the
|
// An existential conforms to a protocol if the protocol is listed in the
|
||||||
// existential's list of conformances and the existential conforms to
|
// existential's list of conformances and the existential conforms to
|
||||||
// itself.
|
// itself.
|
||||||
if (type->isExistentialType()) {
|
if (type->isExistentialType())
|
||||||
// If the existential type cannot be represented or the protocol does not
|
return lookupExistentialConformance(type, protocol);
|
||||||
// conform to itself, there's no point in looking further.
|
|
||||||
if (!protocol->existentialConformsToSelf())
|
|
||||||
return None;
|
|
||||||
|
|
||||||
auto layout = type->getExistentialLayout();
|
|
||||||
|
|
||||||
// Due to an IRGen limitation, witness tables cannot be passed from an
|
|
||||||
// existential to an archetype parameter, so for now we restrict this to
|
|
||||||
// @objc protocols.
|
|
||||||
if (!layout.isObjC())
|
|
||||||
return None;
|
|
||||||
|
|
||||||
// If the existential is class-constrained, the class might conform
|
|
||||||
// concretely.
|
|
||||||
if (auto superclass = layout.explicitSuperclass) {
|
|
||||||
if (auto result = lookupConformance(superclass, protocol))
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, the existential might conform abstractly.
|
|
||||||
for (auto proto : layout.getProtocols()) {
|
|
||||||
auto *protoDecl = proto->getDecl();
|
|
||||||
|
|
||||||
// If we found the protocol we're looking for, return an abstract
|
|
||||||
// conformance to it.
|
|
||||||
if (protoDecl == protocol)
|
|
||||||
return ProtocolConformanceRef(protocol);
|
|
||||||
|
|
||||||
// If the protocol has a superclass constraint, we might conform
|
|
||||||
// concretely.
|
|
||||||
if (auto superclass = protoDecl->getSuperclass()) {
|
|
||||||
if (auto result = lookupConformance(superclass, protocol))
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now check refined protocols.
|
|
||||||
if (protoDecl->inheritsFrom(protocol))
|
|
||||||
return ProtocolConformanceRef(protocol);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We didn't find our protocol in the existential's list; it doesn't
|
|
||||||
// conform.
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Type variables have trivial conformances.
|
// Type variables have trivial conformances.
|
||||||
if (type->isTypeVariableOrMember())
|
if (type->isTypeVariableOrMember())
|
||||||
|
|||||||
@@ -112,12 +112,6 @@ ProtocolConformanceRef::subst(Type origType,
|
|||||||
if (substType->isOpenedExistential())
|
if (substType->isOpenedExistential())
|
||||||
return *this;
|
return *this;
|
||||||
|
|
||||||
// If the substituted type is an existential, we have a self-conforming
|
|
||||||
// existential being substituted in place of itself. There's no
|
|
||||||
// conformance information in this case, so just return.
|
|
||||||
if (substType->isObjCExistentialType())
|
|
||||||
return *this;
|
|
||||||
|
|
||||||
auto *proto = getRequirement();
|
auto *proto = getRequirement();
|
||||||
|
|
||||||
// Check the conformance map.
|
// Check the conformance map.
|
||||||
@@ -126,7 +120,13 @@ ProtocolConformanceRef::subst(Type origType,
|
|||||||
return *result;
|
return *result;
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm_unreachable("Invalid conformance substitution");
|
// The only remaining case is that the type is an existential that
|
||||||
|
// self-conforms.
|
||||||
|
assert(substType->isExistentialType());
|
||||||
|
auto optConformance =
|
||||||
|
proto->getModuleContext()->lookupExistentialConformance(substType, proto);
|
||||||
|
assert(optConformance && "existential type didn't self-conform");
|
||||||
|
return *optConformance;
|
||||||
}
|
}
|
||||||
|
|
||||||
Type
|
Type
|
||||||
|
|||||||
Reference in New Issue
Block a user