mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Merge pull request #20619 from rjmccall/self-conformance-fixes
Assorted fixes for the self-conformance infrastructure
This commit is contained in:
@@ -183,7 +183,7 @@ types where the metadata itself has unknown layout.)
|
||||
global ::= type label-list? 'D' // type mangling for the debugger with label list for function types.
|
||||
global ::= type 'TC' // continuation prototype (not actually used for real symbols)
|
||||
global ::= protocol-conformance entity 'TW' // protocol witness thunk
|
||||
global ::= protocol-conformance entity 'TS' // protocol self-conformance witness thunk
|
||||
global ::= entity 'TS' // protocol self-conformance witness thunk
|
||||
global ::= context identifier identifier 'TB' // property behavior initializer thunk (not used currently)
|
||||
global ::= context identifier identifier 'Tb' // property behavior setter thunk (not used currently)
|
||||
global ::= global specialization // function specialization
|
||||
|
||||
@@ -364,6 +364,33 @@ public:
|
||||
ConcreteDeclRef getWitnessDeclRef(ValueDecl *requirement,
|
||||
LazyResolver *resolver) const;
|
||||
|
||||
/// Apply the given function object to each value witness within this
|
||||
/// protocol conformance.
|
||||
///
|
||||
/// The function object should accept a \c ValueDecl* for the requirement
|
||||
/// followed by the \c Witness for the witness. Note that a generic
|
||||
/// witness will only be specialized if the conformance came from the current
|
||||
/// file.
|
||||
template<typename F>
|
||||
void forEachValueWitness(LazyResolver *resolver, F f) const {
|
||||
const ProtocolDecl *protocol = getProtocol();
|
||||
for (auto req : protocol->getMembers()) {
|
||||
auto valueReq = dyn_cast<ValueDecl>(req);
|
||||
if (!valueReq || isa<AssociatedTypeDecl>(valueReq) ||
|
||||
valueReq->isInvalid())
|
||||
continue;
|
||||
|
||||
if (!valueReq->isProtocolRequirement())
|
||||
continue;
|
||||
|
||||
// If we don't have and cannot resolve witnesses, skip it.
|
||||
if (!resolver && !hasWitness(valueReq))
|
||||
continue;
|
||||
|
||||
f(valueReq, getWitness(valueReq, resolver));
|
||||
}
|
||||
}
|
||||
|
||||
static bool classof(const ProtocolConformance *conformance) {
|
||||
return conformance->getKind() == ProtocolConformanceKind::Normal ||
|
||||
conformance->getKind() == ProtocolConformanceKind::Self;
|
||||
@@ -639,33 +666,6 @@ public:
|
||||
/// Set the witness for the given requirement.
|
||||
void setWitness(ValueDecl *requirement, Witness witness) const;
|
||||
|
||||
/// Apply the given function object to each value witness within this
|
||||
/// protocol conformance.
|
||||
///
|
||||
/// The function object should accept a \c ValueDecl* for the requirement
|
||||
/// followed by the \c Witness for the witness. Note that a generic
|
||||
/// witness will only be specialized if the conformance came from the current
|
||||
/// file.
|
||||
template<typename F>
|
||||
void forEachValueWitness(LazyResolver *resolver, F f) const {
|
||||
const ProtocolDecl *protocol = getProtocol();
|
||||
for (auto req : protocol->getMembers()) {
|
||||
auto valueReq = dyn_cast<ValueDecl>(req);
|
||||
if (!valueReq || isa<AssociatedTypeDecl>(valueReq) ||
|
||||
valueReq->isInvalid())
|
||||
continue;
|
||||
|
||||
if (!valueReq->isProtocolRequirement())
|
||||
continue;
|
||||
|
||||
// If we don't have and cannot resolve witnesses, skip it.
|
||||
if (!resolver && !hasWitness(valueReq))
|
||||
continue;
|
||||
|
||||
f(valueReq, getWitness(valueReq, resolver));
|
||||
}
|
||||
}
|
||||
|
||||
/// Retrieve the protocol conformances that satisfy the requirements of the
|
||||
/// protocol, which line up with the conformance constraints in the
|
||||
/// protocol's requirement signature.
|
||||
|
||||
@@ -201,10 +201,7 @@ std::string ASTMangler::mangleWitnessThunk(
|
||||
beginMangling();
|
||||
// Concrete witness thunks get a special mangling.
|
||||
if (Conformance) {
|
||||
if (auto selfConformance = dyn_cast<SelfProtocolConformance>(Conformance)) {
|
||||
auto protocol = cast<SelfProtocolConformance>(Conformance)->getProtocol();
|
||||
appendProtocolName(protocol);
|
||||
} else {
|
||||
if (!isa<SelfProtocolConformance>(Conformance)) {
|
||||
appendProtocolConformance(Conformance);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1720,7 +1720,7 @@ void Remangler::mangleProtocolRequirementsBaseDescriptor(Node *node) {
|
||||
}
|
||||
|
||||
void Remangler::mangleProtocolSelfConformanceDescriptor(Node *node) {
|
||||
mangleProtocol(node->getChild(0));
|
||||
manglePureProtocol(node->getChild(0));
|
||||
Buffer << "MS";
|
||||
}
|
||||
|
||||
|
||||
@@ -1001,8 +1001,15 @@ static bool hasDependentTypeWitness(const RootProtocolConformance *root) {
|
||||
}
|
||||
|
||||
static bool isDependentConformance(
|
||||
const NormalProtocolConformance *conformance,
|
||||
const RootProtocolConformance *rootConformance,
|
||||
llvm::SmallPtrSet<const NormalProtocolConformance *, 4> &visited){
|
||||
// Self-conformances are never dependent.
|
||||
auto conformance = dyn_cast<NormalProtocolConformance>(rootConformance);
|
||||
if (!conformance)
|
||||
return false;
|
||||
|
||||
// Check whether we've visited this conformance already. If so,
|
||||
// optimistically assume it's fine --- we want the maximal fixed point.
|
||||
if (!visited.insert(conformance).second)
|
||||
return false;
|
||||
|
||||
@@ -1024,7 +1031,7 @@ static bool isDependentConformance(
|
||||
conformance->getAssociatedConformance(req.getFirstType(), assocProtocol);
|
||||
if (assocConformance.isAbstract() ||
|
||||
isDependentConformance(assocConformance.getConcrete()
|
||||
->getRootNormalConformance(),
|
||||
->getRootConformance(),
|
||||
visited))
|
||||
return true;
|
||||
}
|
||||
@@ -1040,18 +1047,11 @@ static bool isDependentConformance(
|
||||
|
||||
/// Is there anything about the given conformance that requires witness
|
||||
/// tables to be dependently-generated?
|
||||
static bool isDependentConformance(
|
||||
const NormalProtocolConformance *conformance) {
|
||||
static bool isDependentConformance(const RootProtocolConformance *conformance) {
|
||||
llvm::SmallPtrSet<const NormalProtocolConformance *, 4> visited;
|
||||
return ::isDependentConformance(conformance, visited);
|
||||
}
|
||||
|
||||
static bool isDependentConformance(const RootProtocolConformance *conformance) {
|
||||
if (auto normal = dyn_cast<NormalProtocolConformance>(conformance))
|
||||
return isDependentConformance(normal);
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool isSynthesizedNonUnique(const RootProtocolConformance *conformance) {
|
||||
if (auto normal = dyn_cast<NormalProtocolConformance>(conformance))
|
||||
return normal->isSynthesizedNonUnique();
|
||||
|
||||
@@ -212,7 +212,7 @@ std::string LinkEntity::mangleAsString() const {
|
||||
|
||||
case Kind::ProtocolConformanceDescriptor:
|
||||
return mangler.mangleProtocolConformanceDescriptor(
|
||||
cast<NormalProtocolConformance>(getProtocolConformance()));
|
||||
getRootProtocolConformance());
|
||||
|
||||
case Kind::EnumCase:
|
||||
return mangler.mangleEnumCase(getDecl());
|
||||
@@ -353,7 +353,7 @@ SILLinkage LinkEntity::getLinkage(ForDefinition_t forDefinition) const {
|
||||
// For when `this` is a protocol conformance of some kind.
|
||||
auto getLinkageAsConformance = [&] {
|
||||
return getLinkageForProtocolConformance(
|
||||
getProtocolConformance()->getRootNormalConformance(), forDefinition);
|
||||
getProtocolConformance()->getRootConformance(), forDefinition);
|
||||
};
|
||||
|
||||
switch (getKind()) {
|
||||
|
||||
@@ -41,8 +41,7 @@ LocalTypeDataKind LocalTypeDataKind::getCachingKind() const {
|
||||
|
||||
// Map protocol conformances to their root normal conformance.
|
||||
auto conformance = getConcreteProtocolConformance();
|
||||
return forConcreteProtocolWitnessTable(
|
||||
conformance->getRootNormalConformance());
|
||||
return forConcreteProtocolWitnessTable(conformance->getRootConformance());
|
||||
}
|
||||
|
||||
LocalTypeDataCache &IRGenFunction::getOrCreateLocalTypeData() {
|
||||
|
||||
@@ -4137,6 +4137,7 @@ void Serializer::writeAllDeclsAndTypes() {
|
||||
|
||||
registerDeclTypeAbbr<AbstractProtocolConformanceLayout>();
|
||||
registerDeclTypeAbbr<NormalProtocolConformanceLayout>();
|
||||
registerDeclTypeAbbr<SelfProtocolConformanceLayout>();
|
||||
registerDeclTypeAbbr<SpecializedProtocolConformanceLayout>();
|
||||
registerDeclTypeAbbr<InheritedProtocolConformanceLayout>();
|
||||
registerDeclTypeAbbr<InvalidProtocolConformanceLayout>();
|
||||
|
||||
@@ -2424,6 +2424,7 @@ void SILSerializer::writeSILBlock(const SILModule *SILMod) {
|
||||
// decl blocks and sil blocks.
|
||||
registerSILAbbr<decls_block::AbstractProtocolConformanceLayout>();
|
||||
registerSILAbbr<decls_block::NormalProtocolConformanceLayout>();
|
||||
registerSILAbbr<decls_block::SelfProtocolConformanceLayout>();
|
||||
registerSILAbbr<decls_block::SpecializedProtocolConformanceLayout>();
|
||||
registerSILAbbr<decls_block::InheritedProtocolConformanceLayout>();
|
||||
registerSILAbbr<decls_block::NormalProtocolConformanceIdLayout>();
|
||||
|
||||
@@ -132,19 +132,15 @@ void TBDGenVisitor::addConformances(DeclContext *DC) {
|
||||
ValueDecl *witnessDecl) {
|
||||
auto witnessLinkage = SILDeclRef(witnessDecl).getLinkage(ForDefinition);
|
||||
if (conformanceIsFixed &&
|
||||
fixmeWitnessHasLinkageThatNeedsToBePublic(witnessLinkage)) {
|
||||
(isa<SelfProtocolConformance>(rootConformance) ||
|
||||
fixmeWitnessHasLinkageThatNeedsToBePublic(witnessLinkage))) {
|
||||
Mangle::ASTMangler Mangler;
|
||||
addSymbol(
|
||||
Mangler.mangleWitnessThunk(rootConformance, requirementDecl));
|
||||
}
|
||||
};
|
||||
|
||||
// FIXME: skipping witnesses for self-conformances?
|
||||
auto normalConformance =
|
||||
dyn_cast<NormalProtocolConformance>(rootConformance);
|
||||
if (!normalConformance) continue;
|
||||
|
||||
normalConformance->forEachValueWitness(
|
||||
rootConformance->forEachValueWitness(
|
||||
nullptr, [&](ValueDecl *valueReq, Witness witness) {
|
||||
auto witnessDecl = witness.getDecl();
|
||||
if (isa<AbstractFunctionDecl>(valueReq)) {
|
||||
@@ -464,6 +460,9 @@ void TBDGenVisitor::visitProtocolDecl(ProtocolDecl *PD) {
|
||||
addAssociatedTypeDescriptor(assocType);
|
||||
}
|
||||
}
|
||||
|
||||
// Include the self-conformance.
|
||||
addConformances(PD);
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
||||
Reference in New Issue
Block a user