mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[AST] Compute conditional requirements in a conformance.
This allows determining which requirements make a conformance conditional; as in, which requirements aren't known as part of the type itself. Additionally, use this to assert that a few builtin protocols aren't conditionally-conformed-to, something we won't support for now.
This commit is contained in:
@@ -285,6 +285,63 @@ AbstractStorageDecl *ProtocolConformance::getBehaviorDecl() const {
|
||||
return getRootNormalConformance()->getBehaviorDecl();
|
||||
}
|
||||
|
||||
ArrayRef<Requirement> ProtocolConformance::getConditionalRequirements() const {
|
||||
CONFORMANCE_SUBCLASS_DISPATCH(getConditionalRequirements, ());
|
||||
}
|
||||
|
||||
ArrayRef<Requirement>
|
||||
ProtocolConformanceRef::getConditionalRequirements() const {
|
||||
if (isConcrete())
|
||||
return getConcrete()->getConditionalRequirements();
|
||||
else
|
||||
// An abstract conformance is never conditional: any conditionality in the
|
||||
// concrete types that will eventually pass through this at runtime is
|
||||
// completely pre-checked and packaged up.
|
||||
return {};
|
||||
}
|
||||
|
||||
void NormalProtocolConformance::differenceAndStoreConditionalRequirements() {
|
||||
assert(ConditionalRequirements.size() == 0 &&
|
||||
"should not recompute conditional requirements");
|
||||
auto &ctxt = getProtocol()->getASTContext();
|
||||
auto DC = getDeclContext();
|
||||
// Only conformances in extensions can be conditional
|
||||
if (!isa<ExtensionDecl>(DC))
|
||||
return;
|
||||
|
||||
auto typeSig = DC->getAsNominalTypeOrNominalTypeExtensionContext()
|
||||
->getGenericSignature();
|
||||
auto extensionSig = DC->getGenericSignatureOfContext();
|
||||
|
||||
// If the type is generic, the extension should be too, and vice versa.
|
||||
assert((bool)typeSig == (bool)extensionSig &&
|
||||
"unexpected generic-ness mismatch on conformance");
|
||||
if (!typeSig)
|
||||
return;
|
||||
|
||||
auto canExtensionSig = extensionSig->getCanonicalSignature();
|
||||
auto canTypeSig = typeSig->getCanonicalSignature();
|
||||
if (canTypeSig == canExtensionSig)
|
||||
return;
|
||||
|
||||
// The extension signature should be a superset of the type signature, meaning
|
||||
// every thing in the type signature either is included too or is implied by
|
||||
// something else. The most important bit is having the same type
|
||||
// parameters. (NB. if/when Swift gets parameterized extensions, this needs to
|
||||
// change.)
|
||||
assert(canTypeSig.getGenericParams() == canExtensionSig.getGenericParams());
|
||||
|
||||
auto mod = DC->getParentModule();
|
||||
// Find the requirements in the extension that aren't proved by the original
|
||||
// type, these are the ones that make the conformance conditional.
|
||||
SmallVector<Requirement, 4> reqs;
|
||||
for (auto requirement : canExtensionSig->getRequirements()) {
|
||||
if (!canTypeSig->isRequirementSatisfied(requirement))
|
||||
reqs.push_back(requirement);
|
||||
}
|
||||
ConditionalRequirements = ctxt.AllocateCopy(reqs);
|
||||
}
|
||||
|
||||
void NormalProtocolConformance::setSignatureConformances(
|
||||
ArrayRef<ProtocolConformanceRef> conformances) {
|
||||
auto &ctx = getProtocol()->getASTContext();
|
||||
@@ -635,11 +692,24 @@ SpecializedProtocolConformance::SpecializedProtocolConformance(
|
||||
GenericSubstitutions(substitutions)
|
||||
{
|
||||
assert(genericConformance->getKind() != ProtocolConformanceKind::Specialized);
|
||||
|
||||
// Substitute the conditional requirements so that they're phrased in terms of
|
||||
// the specialized types, not the conformance-declaring decl's types.
|
||||
auto subMap = getSubstitutionMap();
|
||||
SmallVector<Requirement, 4> newReqs;
|
||||
for (auto oldReq : GenericConformance->getConditionalRequirements()) {
|
||||
newReqs.push_back(*oldReq.subst(subMap));
|
||||
}
|
||||
auto &ctxt = getProtocol()->getASTContext();
|
||||
ConditionalRequirements = ctxt.AllocateCopy(newReqs);
|
||||
}
|
||||
|
||||
SubstitutionMap SpecializedProtocolConformance::getSubstitutionMap() const {
|
||||
auto *genericSig = GenericConformance->getGenericSignature();
|
||||
return genericSig->getSubstitutionMap(GenericSubstitutions);
|
||||
if (genericSig)
|
||||
return genericSig->getSubstitutionMap(GenericSubstitutions);
|
||||
|
||||
return SubstitutionMap();
|
||||
}
|
||||
|
||||
bool SpecializedProtocolConformance::hasTypeWitness(
|
||||
|
||||
Reference in New Issue
Block a user