mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Factor out the search for explicit conformances.
Swift SVN r8151
This commit is contained in:
@@ -481,33 +481,11 @@ specializeTypeWitnesses(ASTContext &ctx,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
LookupConformanceResult Module::lookupConformance(Type type,
|
/// Retrieve the explicit conformance of the given nominal type declaration
|
||||||
ProtocolDecl *protocol,
|
/// to the given protocol.
|
||||||
LazyResolver *resolver) {
|
static std::tuple<NominalTypeDecl *, Decl *, ProtocolConformance *>
|
||||||
ASTContext &ctx = getASTContext();
|
findExplicitConformance(Module *module, NominalTypeDecl *nominal,
|
||||||
|
ProtocolDecl *protocol, LazyResolver *resolver) {
|
||||||
// Check whether we have already cached an answer to this query.
|
|
||||||
ASTContext::ConformsToMap::key_type key(type->getCanonicalType(), protocol);
|
|
||||||
auto known = ctx.ConformsTo.find(key);
|
|
||||||
if (known != ctx.ConformsTo.end()) {
|
|
||||||
// If we conform, return the conformance.
|
|
||||||
if (known->second.getInt()) {
|
|
||||||
return { known->second.getPointer(), ConformanceKind::Conforms };
|
|
||||||
}
|
|
||||||
|
|
||||||
// We don't conform.
|
|
||||||
return { nullptr, ConformanceKind::DoesNotConform };
|
|
||||||
}
|
|
||||||
|
|
||||||
auto nominal = type->getAnyNominal();
|
|
||||||
|
|
||||||
// If we don't have a nominal type, there are no conformances.
|
|
||||||
// FIXME: We may have implicit conformances for some cases. Handle those
|
|
||||||
// here.
|
|
||||||
if (!nominal) {
|
|
||||||
return { nullptr, ConformanceKind::DoesNotConform };
|
|
||||||
}
|
|
||||||
|
|
||||||
// Walk the nominal type, its extensions, superclasses, and so on.
|
// Walk the nominal type, its extensions, superclasses, and so on.
|
||||||
llvm::SmallPtrSet<ProtocolDecl *, 4> visitedProtocols;
|
llvm::SmallPtrSet<ProtocolDecl *, 4> visitedProtocols;
|
||||||
SmallVector<std::tuple<NominalTypeDecl *, NominalTypeDecl *, Decl *>,4> stack;
|
SmallVector<std::tuple<NominalTypeDecl *, NominalTypeDecl *, Decl *>,4> stack;
|
||||||
@@ -522,22 +500,22 @@ LookupConformanceResult Module::lookupConformance(Type type,
|
|||||||
Decl *currentOwner,
|
Decl *currentOwner,
|
||||||
ArrayRef<ProtocolDecl *> protocols,
|
ArrayRef<ProtocolDecl *> protocols,
|
||||||
ArrayRef<ProtocolConformance *> conformances) -> bool {
|
ArrayRef<ProtocolConformance *> conformances) -> bool {
|
||||||
for (unsigned i = 0, n = protocols.size(); i != n; ++i) {
|
for (unsigned i = 0, n = protocols.size(); i != n; ++i) {
|
||||||
auto testProto = protocols[i];
|
auto testProto = protocols[i];
|
||||||
if (testProto == protocol) {
|
if (testProto == protocol) {
|
||||||
owningNominal = currentNominal;
|
owningNominal = currentNominal;
|
||||||
declaresConformance = currentOwner;
|
declaresConformance = currentOwner;
|
||||||
if (i < conformances.size())
|
if (i < conformances.size())
|
||||||
nominalConformance = conformances[i];
|
nominalConformance = conformances[i];
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
if (visitedProtocols.insert(testProto))
|
|
||||||
stack.push_back({testProto, currentNominal, currentOwner});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
if (visitedProtocols.insert(testProto))
|
||||||
};
|
stack.push_back({testProto, currentNominal, currentOwner});
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
// Walk the stack of types to find a conformance.
|
// Walk the stack of types to find a conformance.
|
||||||
stack.push_back({nominal, nominal, nominal});
|
stack.push_back({nominal, nominal, nominal});
|
||||||
@@ -573,29 +551,71 @@ LookupConformanceResult Module::lookupConformance(Type type,
|
|||||||
// If we didn't find the protocol, we don't conform. Cache the negative result
|
// If we didn't find the protocol, we don't conform. Cache the negative result
|
||||||
// and return.
|
// and return.
|
||||||
if (!owningNominal) {
|
if (!owningNominal) {
|
||||||
ctx.ConformsTo[key] = ConformanceEntry(nullptr, false);
|
return { nullptr, nullptr, nullptr };
|
||||||
return { nullptr, ConformanceKind::DoesNotConform };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we found the protocol but we don't have a conformance, it's because
|
// If we don't have a nominal conformance, but we do have a resolver, try
|
||||||
// we haven't type-checked the conformance yet.
|
// to resolve the nominal conformance now.
|
||||||
if (!nominalConformance) {
|
if (!nominalConformance && resolver) {
|
||||||
// When there is no resolver, we simply can't check this.
|
|
||||||
if (!resolver)
|
|
||||||
return { nullptr, ConformanceKind::UncheckedConforms };
|
|
||||||
|
|
||||||
// Try to resolve the conformance.
|
|
||||||
nominalConformance = resolver->resolveConformance(
|
nominalConformance = resolver->resolveConformance(
|
||||||
owningNominal,
|
owningNominal,
|
||||||
protocol,
|
protocol,
|
||||||
dyn_cast<ExtensionDecl>(declaresConformance));
|
dyn_cast<ExtensionDecl>(declaresConformance));
|
||||||
|
}
|
||||||
|
|
||||||
// If we failed to resolve the conformance, then the type doesn't
|
// If we have a nominal conformance, we're done.
|
||||||
// actually conform. Cache the negative result and return.
|
if (nominalConformance) {
|
||||||
if (!nominalConformance) {
|
return { owningNominal, declaresConformance, nominalConformance };
|
||||||
ctx.ConformsTo[key] = ConformanceEntry(nullptr, false);
|
}
|
||||||
return { nullptr, ConformanceKind::DoesNotConform };
|
|
||||||
|
return { nullptr, nullptr, nullptr };
|
||||||
|
}
|
||||||
|
|
||||||
|
LookupConformanceResult Module::lookupConformance(Type type,
|
||||||
|
ProtocolDecl *protocol,
|
||||||
|
LazyResolver *resolver) {
|
||||||
|
ASTContext &ctx = getASTContext();
|
||||||
|
|
||||||
|
// Check whether we have already cached an answer to this query.
|
||||||
|
ASTContext::ConformsToMap::key_type key(type->getCanonicalType(), protocol);
|
||||||
|
auto known = ctx.ConformsTo.find(key);
|
||||||
|
if (known != ctx.ConformsTo.end()) {
|
||||||
|
// If we conform, return the conformance.
|
||||||
|
if (known->second.getInt()) {
|
||||||
|
return { known->second.getPointer(), ConformanceKind::Conforms };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We don't conform.
|
||||||
|
return { nullptr, ConformanceKind::DoesNotConform };
|
||||||
|
}
|
||||||
|
|
||||||
|
auto nominal = type->getAnyNominal();
|
||||||
|
|
||||||
|
// If we don't have a nominal type, there are no conformances.
|
||||||
|
// FIXME: We may have implicit conformances for some cases. Handle those
|
||||||
|
// here.
|
||||||
|
if (!nominal) {
|
||||||
|
return { nullptr, ConformanceKind::DoesNotConform };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the explicit conformance.
|
||||||
|
NominalTypeDecl *owningNominal = nullptr;
|
||||||
|
Decl *declaresConformance = nullptr;
|
||||||
|
ProtocolConformance *nominalConformance = nullptr;
|
||||||
|
std::tie(owningNominal, declaresConformance, nominalConformance)
|
||||||
|
= findExplicitConformance(this, nominal, protocol, resolver);
|
||||||
|
|
||||||
|
// If we didn't find an owning nominal, we don't conform. Cache the negative
|
||||||
|
// result and return.
|
||||||
|
if (!owningNominal) {
|
||||||
|
ctx.ConformsTo[key] = ConformanceEntry(nullptr, false);
|
||||||
|
return { nullptr, ConformanceKind::DoesNotConform };
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we found an owning nominal but didn't have a conformance, this is
|
||||||
|
// an unchecked conformance.
|
||||||
|
if (!nominalConformance) {
|
||||||
|
return { nullptr, ConformanceKind::UncheckedConforms };
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the nominal type in which we found the conformance is not the same
|
// If the nominal type in which we found the conformance is not the same
|
||||||
|
|||||||
Reference in New Issue
Block a user