mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Rework a number of SIL and IRGen witness-table abstractions
to correctly handle generalized protocol requirements. The major missing pieces here are that the conformance search algorithms in both the AST (type substitution) and IRGen (witness table reference emission) need to be rewritten to back-track requirement sources, and the AST needs to actually represent this stuff in NormalProtocolConformances instead of just doing ???. The new generality isn't tested yet; I'm looking into that, but I wanted to get the abstractions in place first.
This commit is contained in:
@@ -336,6 +336,103 @@ void NormalProtocolConformance::setTypeWitness(
|
||||
TypeWitnesses[assocType] = std::make_pair(substitution, typeDecl);
|
||||
}
|
||||
|
||||
/// TypeWitnesses is keyed by the protocol's own declarations, but
|
||||
/// DependentMemberTypes will sometimes store a base protocol's declaration.
|
||||
/// Map to the derived declaration if possible.
|
||||
static AssociatedTypeDecl *getOwnAssociatedTypeDecl(ProtocolDecl *protocol,
|
||||
AssociatedTypeDecl *assoc) {
|
||||
// Fast path.
|
||||
if (assoc->getProtocol() == protocol) return assoc;
|
||||
|
||||
// Search the protocol.
|
||||
for (auto member : protocol->getMembers()) {
|
||||
if (auto memberAssoc = dyn_cast<AssociatedTypeDecl>(member)) {
|
||||
if (memberAssoc->getName() == assoc->getName()) {
|
||||
return memberAssoc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Just assume this is fine.
|
||||
return assoc;
|
||||
}
|
||||
|
||||
Type NormalProtocolConformance::getAssociatedType(Type assocType,
|
||||
LazyResolver *resolver) const {
|
||||
assert(assocType->isTypeParameter() &&
|
||||
"associated type must be a type parameter");
|
||||
|
||||
// Fast path.
|
||||
auto type = assocType->getCanonicalType();
|
||||
if (isa<GenericTypeParamType>(type)) {
|
||||
assert(type->isEqual(getProtocol()->getSelfInterfaceType()) &&
|
||||
"type parameter in protocol was not Self");
|
||||
return getType();
|
||||
}
|
||||
|
||||
auto memberType = cast<DependentMemberType>(type);
|
||||
|
||||
// TODO: make this handle multiple levels of dependent member type.
|
||||
assert(memberType.getBase()->isEqual(getProtocol()->getSelfInterfaceType()) &&
|
||||
"dependent member in protocol was not rooted in Self");
|
||||
|
||||
auto assocTypeDecl =
|
||||
getOwnAssociatedTypeDecl(getProtocol(), memberType->getAssocType());
|
||||
auto &subst = getTypeWitnessSubstAndDecl(assocTypeDecl, resolver).first;
|
||||
return subst.getReplacement();
|
||||
}
|
||||
|
||||
ProtocolConformanceRef
|
||||
NormalProtocolConformance::getAssociatedConformance(Type assocType,
|
||||
ProtocolDecl *protocol,
|
||||
LazyResolver *resolver) const {
|
||||
assert(assocType->isTypeParameter() &&
|
||||
"associated type must be a type parameter");
|
||||
|
||||
#ifndef NDEBUG
|
||||
bool foundInRequirements = false;
|
||||
for (auto &reqt :
|
||||
getProtocol()->getRequirementSignature()->getRequirements()) {
|
||||
if (reqt.getKind() == RequirementKind::Conformance &&
|
||||
reqt.getFirstType()->isEqual(assocType) &&
|
||||
reqt.getSecondType()->castTo<ProtocolType>()->getDecl() == protocol) {
|
||||
foundInRequirements = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(foundInRequirements &&
|
||||
"requested conformance was not a direct requirement of the protocol");
|
||||
#endif
|
||||
|
||||
auto type = assocType->getCanonicalType();
|
||||
|
||||
if (isa<GenericTypeParamType>(type)) {
|
||||
assert(type->isEqual(getProtocol()->getSelfInterfaceType()) &&
|
||||
"type parameter in protocol was not Self");
|
||||
auto conf = getInheritedConformance(protocol);
|
||||
assert(conf && "inherited conformances cannot be abstract");
|
||||
return ProtocolConformanceRef(conf);
|
||||
}
|
||||
|
||||
auto memberType = cast<DependentMemberType>(type);
|
||||
|
||||
// For now, NormalProtocolConformance does not store indirect associations.
|
||||
assert(memberType.getBase()->isEqual(getProtocol()->getSelfInterfaceType()) &&
|
||||
"dependent member in protocol was not rooted in Self");
|
||||
|
||||
auto assocTypeDecl =
|
||||
getOwnAssociatedTypeDecl(getProtocol(), memberType->getAssocType());
|
||||
auto &subst = getTypeWitnessSubstAndDecl(assocTypeDecl, resolver).first;
|
||||
|
||||
// Scan the conformances for the exact conformance.
|
||||
// TODO: should we allow indirect conformances for convenience of use?
|
||||
for (auto &conf : subst.getConformances()) {
|
||||
if (conf.getRequirement() == protocol)
|
||||
return conf;
|
||||
}
|
||||
llvm_unreachable("missing conformance to protocol");
|
||||
}
|
||||
|
||||
/// Retrieve the value witness corresponding to the given requirement.
|
||||
Witness NormalProtocolConformance::getWitness(ValueDecl *requirement,
|
||||
LazyResolver *resolver) const {
|
||||
|
||||
Reference in New Issue
Block a user