[Module file] (De-)serialize inherited protocol conformances.

Swift SVN r6886
This commit is contained in:
Doug Gregor
2013-08-05 14:29:16 +00:00
parent 8956e856c6
commit 1bd583cdf8
4 changed files with 143 additions and 69 deletions

View File

@@ -198,6 +198,47 @@ Pattern *ModuleFile::maybeReadPattern() {
} }
} }
ProtocolConformance *
ModuleFile::readUnderlyingConformance(ProtocolDecl *proto,
DeclID nominalID,
IdentifierID moduleOrTypeID) {
if (!nominalID) {
// The underlying conformance is in the following record.
return maybeReadConformance(getType(moduleOrTypeID))->second;
}
// Dig out the protocol conformance within the nominal declaration.
auto nominal = cast<NominalTypeDecl>(getDecl(nominalID));
Module *owningModule;
if (moduleOrTypeID == 0)
owningModule = ModuleContext;
else
owningModule = getModule(getIdentifier(moduleOrTypeID-1));
(void)owningModule; // FIXME: Currently only used for checking.
// Search protocols
for (unsigned i = 0, n = nominal->getProtocols().size(); i != n; ++i) {
if (nominal->getProtocols()[i] == proto) {
// FIXME: Eventually, filter by owning module.
assert(nominal->getModuleContext() == owningModule);
return nominal->getConformances()[i];
}
}
// Search extensions.
for (auto ext : nominal->getExtensions()) {
for (unsigned i = 0, n = ext->getProtocols().size(); i != n; ++i) {
if (ext->getProtocols()[i] == proto) {
// FIXME: Eventually, filter by owning module.
assert(ext->getModuleContext() == owningModule);
return ext->getConformances()[i];
}
}
}
llvm_unreachable("Unable to find underlying conformance");
}
Optional<ConformancePair> ModuleFile::maybeReadConformance(Type conformingType){ Optional<ConformancePair> ModuleFile::maybeReadConformance(Type conformingType){
using namespace decls_block; using namespace decls_block;
@@ -222,8 +263,6 @@ Optional<ConformancePair> ModuleFile::maybeReadConformance(Type conformingType){
break; break;
case SPECIALIZED_PROTOCOL_CONFORMANCE: { case SPECIALIZED_PROTOCOL_CONFORMANCE: {
lastRecordOffset.reset();
DeclID protoID; DeclID protoID;
DeclID nominalID; DeclID nominalID;
IdentifierID moduleOrTypeID; IdentifierID moduleOrTypeID;
@@ -262,51 +301,12 @@ Optional<ConformancePair> ModuleFile::maybeReadConformance(Type conformingType){
} }
assert(rawIDIter <= rawIDs.end() && "read too much"); assert(rawIDIter <= rawIDs.end() && "read too much");
ProtocolConformance *genericConformance
= readUnderlyingConformance(proto, nominalID, moduleOrTypeID);
// Reset the offset RAII to the end of the trailing records. // Reset the offset RAII to the end of the trailing records.
lastRecordOffset.reset(); lastRecordOffset.reset();
ProtocolConformance *genericConformance = nullptr;
if (nominalID) {
// Dig out the protocol conformance within the nominal declaration.
auto nominal = cast<NominalTypeDecl>(getDecl(nominalID));
Module *owningModule;
if (moduleOrTypeID == 0)
owningModule = ModuleContext;
else
owningModule = getModule(getIdentifier(moduleOrTypeID-1));
(void)owningModule; // FIXME: Currently only used for checking.
for (unsigned i = 0, n = nominal->getProtocols().size(); i != n; ++i) {
if (nominal->getProtocols()[i] == proto) {
genericConformance = nominal->getConformances()[i];
// FIXME: Eventually, filter by owning module.
assert(nominal->getModuleContext() == owningModule);
break;
}
}
if (!genericConformance) {
for (auto ext : nominal->getExtensions()) {
for (unsigned i = 0, n = ext->getProtocols().size(); i != n; ++i) {
if (ext->getProtocols()[i] == proto) {
genericConformance = ext->getConformances()[i];
// FIXME: Eventually, filter by owning module.
assert(ext->getModuleContext() == owningModule);
break;
}
}
if (genericConformance)
break;
}
}
} else {
// The generic conformance is in the following record.
genericConformance
= maybeReadConformance(getType(moduleOrTypeID))->second;
}
assert(genericConformance && "Missing generic conformance?"); assert(genericConformance && "Missing generic conformance?");
return { proto, return { proto,
ctx.getSpecializedConformance(conformingType, ctx.getSpecializedConformance(conformingType,
@@ -316,10 +316,28 @@ Optional<ConformancePair> ModuleFile::maybeReadConformance(Type conformingType){
} }
case INHERITED_PROTOCOL_CONFORMANCE: { case INHERITED_PROTOCOL_CONFORMANCE: {
// FIXME: Does this even make sense? DeclID protoID;
llvm_unreachable("Not implemented"); DeclID nominalID;
} IdentifierID moduleOrTypeID;
InheritedProtocolConformanceLayout::readRecord(scratch, protoID,
nominalID,
moduleOrTypeID);
ASTContext &ctx = ModuleContext->Ctx;
auto proto = cast<ProtocolDecl>(getDecl(protoID));
ProtocolConformance *inheritedConformance
= readUnderlyingConformance(proto, nominalID, moduleOrTypeID);
// Reset the offset RAII to the end of the trailing records.
lastRecordOffset.reset();
assert(inheritedConformance && "Missing generic conformance?");
return { proto,
ctx.getInheritedConformance(conformingType,
inheritedConformance) };
}
// Not a protocol conformance. // Not a protocol conformance.
default: default:
return Nothing; return Nothing;

View File

@@ -194,6 +194,13 @@ private:
/// If the record at the cursor is not a pattern, returns null. /// If the record at the cursor is not a pattern, returns null.
Pattern *maybeReadPattern(); Pattern *maybeReadPattern();
/// Read the underlying conformance for a specialized or inherited
/// protocol conformance.
ProtocolConformance *
readUnderlyingConformance(ProtocolDecl *proto,
serialization::DeclID nominalID,
serialization::IdentifierID moduleOrTypeID);
/// Recursively reads a protocol conformance from \c DeclTypeCursor. /// Recursively reads a protocol conformance from \c DeclTypeCursor.
/// ///
/// The conformance will be newly-created; it's likely that it already exists /// The conformance will be newly-created; it's likely that it already exists

View File

@@ -666,10 +666,10 @@ namespace decls_block {
using SpecializedProtocolConformanceLayout = BCRecordLayout< using SpecializedProtocolConformanceLayout = BCRecordLayout<
SPECIALIZED_PROTOCOL_CONFORMANCE, SPECIALIZED_PROTOCOL_CONFORMANCE,
DeclIDField, // the protocol DeclIDField, // the protocol
DeclIDField, // the nominal type decl for the normal conformance, DeclIDField, // the nominal type decl for the generic conformance,
// or zero to indicate that the generic conformance // or zero to indicate that the generic conformance
// is in the following record // is in the following record
IdentifierIDField, // the module in which the normal conformance occurs, IdentifierIDField, // the module in which the generic conformance occurs,
// or the conforming type for the generic conformance // or the conforming type for the generic conformance
// record that follows // record that follows
BCVBR<5>, // type mapping count BCVBR<5>, // type mapping count
@@ -681,7 +681,13 @@ namespace decls_block {
using InheritedProtocolConformanceLayout = BCRecordLayout< using InheritedProtocolConformanceLayout = BCRecordLayout<
INHERITED_PROTOCOL_CONFORMANCE, INHERITED_PROTOCOL_CONFORMANCE,
DeclIDField // the protocol DeclIDField, // the protocol
DeclIDField, // the nominal type decl for the inherited conformance,
// or zero to indicate that the inherited conformance
// is in the following record
IdentifierIDField // the module in which the inherited conformance occurs,
// or the conforming type for the inherited conformance
// record that follows
>; >;
using DeclContextLayout = BCRecordLayout< using DeclContextLayout = BCRecordLayout<

View File

@@ -190,6 +190,23 @@ namespace {
/// Writes a list of generic substitutions. /// Writes a list of generic substitutions.
void writeSubstitutions(ArrayRef<Substitution> substitutions); void writeSubstitutions(ArrayRef<Substitution> substitutions);
/// Encode the underlying conformance of a generic or specialized
/// conformance.
///
/// \param conformance The conformance we're encoding.
///
/// \param nominalID Will be set to the "nominal ID" value to be stored
/// in the parent record.
///
/// \param moduleOrTypeID Will be set to the "module or type ID" value to
/// be stored in the parent record.
///
/// \returns true if the underlying conformance will need to be written
/// out as its own record following the parent record.
bool encodeUnderlyingConformance(const ProtocolConformance *conformance,
DeclID &nominalID,
IdentifierID &moduleOrTypeID);
/// Writes a protocol conformance. /// Writes a protocol conformance.
void writeConformance(const ProtocolDecl *protocol, void writeConformance(const ProtocolDecl *protocol,
const ProtocolConformance *conformance); const ProtocolConformance *conformance);
@@ -707,6 +724,30 @@ bool Serializer::writeGenericParams(const GenericParamList *genericParams) {
return true; return true;
} }
bool
Serializer::encodeUnderlyingConformance(const ProtocolConformance *conformance,
DeclID &nominalID,
IdentifierID &moduleOrTypeID) {
bool append = !isa<NormalProtocolConformance>(conformance);
if (append) {
// Set nominalID to 0 to indicate that the generic conformance will
// follow. Encode the type in moduleOrTypeID.
nominalID = 0;
moduleOrTypeID = addTypeRef(conformance->getType());
} else {
nominalID = addDeclRef(conformance->getType()->getAnyNominal());
assert(nominalID && "Missing nominal type for specialized conformance");
// Use '0' to mean 'this module', and add 1 to any other module reference.
if (conformance->getContainingModule() == TU)
moduleOrTypeID = 0;
else
moduleOrTypeID = addModuleRef(conformance->getContainingModule()) + 1;
}
return append;
}
void void
Serializer::writeConformance(const ProtocolDecl *protocol, Serializer::writeConformance(const ProtocolDecl *protocol,
const ProtocolConformance *conformance) { const ProtocolConformance *conformance) {
@@ -786,23 +827,8 @@ Serializer::writeConformance(const ProtocolDecl *protocol,
IdentifierID moduleOrTypeID; IdentifierID moduleOrTypeID;
bool appendGenericConformance bool appendGenericConformance
= !isa<NormalProtocolConformance>(conf->getGenericConformance()); = encodeUnderlyingConformance(conf->getGenericConformance(),
if (appendGenericConformance) { nominalID, moduleOrTypeID);
// Set nominalID to 0 to indicate that the generic conformance will
// follow. Encode the type in moduleOrTypeID.
nominalID = 0;
moduleOrTypeID = addTypeRef(conf->getGenericConformance()->getType());
} else {
nominalID
= addDeclRef(conf->getGenericConformance()->getType()->getAnyNominal());
assert(nominalID && "Missing nominal type for specialized conformance");
// Use '0' to mean 'this module', and add 1 to any other module reference.
if (conf->getContainingModule() == TU)
moduleOrTypeID = 0;
else
moduleOrTypeID = addModuleRef(conf->getContainingModule()) + 1;
}
SpecializedProtocolConformanceLayout::emitRecord(Out, ScratchRecord, SpecializedProtocolConformanceLayout::emitRecord(Out, ScratchRecord,
abbrCode, abbrCode,
@@ -823,8 +849,25 @@ Serializer::writeConformance(const ProtocolDecl *protocol,
} }
case ProtocolConformanceKind::Inherited: { case ProtocolConformanceKind::Inherited: {
// FIXME: inherited conformance might not make sense? auto conf = cast<InheritedProtocolConformance>(conformance);
llvm_unreachable("Not implemented"); unsigned abbrCode
= DeclTypeAbbrCodes[InheritedProtocolConformanceLayout::Code];
DeclID nominalID;
IdentifierID moduleOrTypeID;
bool appendInheritedConformance
= encodeUnderlyingConformance(conf->getInheritedConformance(),
nominalID, moduleOrTypeID);
InheritedProtocolConformanceLayout::emitRecord(Out, ScratchRecord,
abbrCode,
addDeclRef(protocol),
nominalID,
moduleOrTypeID);
if (appendInheritedConformance) {
writeConformance(protocol, conf->getInheritedConformance());
}
break;
} }
} }
} }