Infer ConcurrentValue conformances for structs and enums.

When a struct or enum has only ConcurrentValue-conforming instance
data, infer conformance to ConcurrentValue.
This commit is contained in:
Doug Gregor
2021-03-02 00:23:33 -08:00
parent 9962e860f1
commit b5e4b085aa
23 changed files with 336 additions and 52 deletions

View File

@@ -967,6 +967,17 @@ ModuleDecl::lookupExistentialConformance(Type type, ProtocolDecl *protocol) {
ProtocolConformanceRef ModuleDecl::lookupConformance(Type type,
ProtocolDecl *protocol) {
// If we are recursively checking for implicit conformance of a nominal
// type to ConcurrentValue, fail without evaluating this request. This
// squashes cycles.
if (protocol->isSpecificProtocol(KnownProtocolKind::ConcurrentValue)) {
if (auto nominal = type->getAnyNominal()) {
GetImplicitConcurrentValueRequest request{nominal};
if (getASTContext().evaluator.hasActiveRequest(request))
return ProtocolConformanceRef::forInvalid();
}
}
return evaluateOrDefault(
getASTContext().evaluator,
LookupConformanceInModuleRequest{{this, type, protocol}},
@@ -1035,8 +1046,20 @@ LookupConformanceInModuleRequest::evaluate(
// Find the (unspecialized) conformance.
SmallVector<ProtocolConformance *, 2> conformances;
if (!nominal->lookupConformance(mod, protocol, conformances))
return ProtocolConformanceRef::forInvalid();
if (!nominal->lookupConformance(mod, protocol, conformances)) {
if (!protocol->isSpecificProtocol(KnownProtocolKind::ConcurrentValue))
return ProtocolConformanceRef::forInvalid();
// Try to infer ConcurrentValue conformance.
GetImplicitConcurrentValueRequest cvRequest{nominal};
if (auto conformance = evaluateOrDefault(
ctx.evaluator, cvRequest, nullptr)) {
conformances.clear();
conformances.push_back(conformance);
} else {
return ProtocolConformanceRef::forInvalid();
}
}
// FIXME: Ambiguity resolution.
auto conformance = conformances.front();