AST: Tweak conformance lookup for class-constrained archetypes

The comment explains the situation; now that we drop protocol
conformance requirements that are made redundant by a superclass
requirement, we necessarily have to prefer returning a concrete
conformance here rather than an abstract one, because an
abstract one will not be fulfilled by a substitution that
makes the archetype concrete, since there's no explicit
conformance requirement to fulfill.
This commit is contained in:
Slava Pestov
2016-09-02 22:35:14 -07:00
parent 19c982bcd9
commit c28529315b

View File

@@ -668,8 +668,25 @@ Module::lookupConformance(Type type, ProtocolDecl *protocol,
ASTContext &ctx = getASTContext(); ASTContext &ctx = getASTContext();
// An archetype conforms to a protocol if the protocol is listed in the // An archetype conforms to a protocol if the protocol is listed in the
// archetype's list of conformances. // archetype's list of conformances, or if the archetype has a superclass
// constraint and the superclass conforms to the protocol.
if (auto archetype = type->getAs<ArchetypeType>()) { if (auto archetype = type->getAs<ArchetypeType>()) {
// The archetype builder drops conformance requirements that are made
// redundant by a superclass requirement, so check for a cocnrete
// conformance first, since an abstract conformance might not be
// able to be resolved by a substitution that makes the archetype
// concrete.
if (auto super = archetype->getSuperclass()) {
if (auto inheritedConformance = lookupConformance(super, protocol,
resolver)) {
return ProtocolConformanceRef(
ctx.getInheritedConformance(
type,
inheritedConformance->getConcrete()));
}
}
if (protocol->isSpecificProtocol(KnownProtocolKind::AnyObject)) { if (protocol->isSpecificProtocol(KnownProtocolKind::AnyObject)) {
if (archetype->requiresClass()) if (archetype->requiresClass())
return ProtocolConformanceRef(protocol); return ProtocolConformanceRef(protocol);
@@ -682,8 +699,7 @@ Module::lookupConformance(Type type, ProtocolDecl *protocol,
return ProtocolConformanceRef(protocol); return ProtocolConformanceRef(protocol);
} }
if (!archetype->getSuperclass()) return None;
return None;
} }
// 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
@@ -727,21 +743,6 @@ Module::lookupConformance(Type type, ProtocolDecl *protocol,
return None; return None;
} }
// Check for protocol conformance of archetype via superclass requirement.
if (auto archetype = type->getAs<ArchetypeType>()) {
if (auto super = archetype->getSuperclass()) {
if (auto inheritedConformance = lookupConformance(super, protocol,
resolver)) {
return ProtocolConformanceRef(
ctx.getInheritedConformance(
type,
inheritedConformance->getConcrete()));
}
return None;
}
}
// UnresolvedType is a placeholder for an unknown type used when generating // UnresolvedType is a placeholder for an unknown type used when generating
// diagnostics. We consider it to conform to all protocols, since the // diagnostics. We consider it to conform to all protocols, since the
// intended type might have. // intended type might have.
@@ -750,8 +751,7 @@ Module::lookupConformance(Type type, ProtocolDecl *protocol,
ctx.getConformance(type, protocol, protocol->getLoc(), this, ctx.getConformance(type, protocol, protocol->getLoc(), this,
ProtocolConformanceState::Complete)); ProtocolConformanceState::Complete));
} }
auto nominal = type->getAnyNominal(); auto nominal = type->getAnyNominal();
// If we don't have a nominal type, there are no conformances. // If we don't have a nominal type, there are no conformances.