Merge pull request #20619 from rjmccall/self-conformance-fixes

Assorted fixes for the self-conformance infrastructure
This commit is contained in:
John McCall
2018-11-15 23:18:53 -05:00
committed by GitHub
10 changed files with 51 additions and 54 deletions

View File

@@ -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

View File

@@ -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.

View File

@@ -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);
}
}

View File

@@ -1720,7 +1720,7 @@ void Remangler::mangleProtocolRequirementsBaseDescriptor(Node *node) {
}
void Remangler::mangleProtocolSelfConformanceDescriptor(Node *node) {
mangleProtocol(node->getChild(0));
manglePureProtocol(node->getChild(0));
Buffer << "MS";
}

View File

@@ -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();

View File

@@ -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()) {

View File

@@ -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() {

View File

@@ -4137,6 +4137,7 @@ void Serializer::writeAllDeclsAndTypes() {
registerDeclTypeAbbr<AbstractProtocolConformanceLayout>();
registerDeclTypeAbbr<NormalProtocolConformanceLayout>();
registerDeclTypeAbbr<SelfProtocolConformanceLayout>();
registerDeclTypeAbbr<SpecializedProtocolConformanceLayout>();
registerDeclTypeAbbr<InheritedProtocolConformanceLayout>();
registerDeclTypeAbbr<InvalidProtocolConformanceLayout>();

View File

@@ -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>();

View File

@@ -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