mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[Module file] (De-)serialize inherited protocol conformances.
Swift SVN r6886
This commit is contained in:
@@ -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){
|
||||
using namespace decls_block;
|
||||
|
||||
@@ -222,8 +263,6 @@ Optional<ConformancePair> ModuleFile::maybeReadConformance(Type conformingType){
|
||||
break;
|
||||
|
||||
case SPECIALIZED_PROTOCOL_CONFORMANCE: {
|
||||
lastRecordOffset.reset();
|
||||
|
||||
DeclID protoID;
|
||||
DeclID nominalID;
|
||||
IdentifierID moduleOrTypeID;
|
||||
@@ -262,51 +301,12 @@ Optional<ConformancePair> ModuleFile::maybeReadConformance(Type conformingType){
|
||||
}
|
||||
assert(rawIDIter <= rawIDs.end() && "read too much");
|
||||
|
||||
ProtocolConformance *genericConformance
|
||||
= readUnderlyingConformance(proto, nominalID, moduleOrTypeID);
|
||||
|
||||
// Reset the offset RAII to the end of the trailing records.
|
||||
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?");
|
||||
return { proto,
|
||||
ctx.getSpecializedConformance(conformingType,
|
||||
@@ -316,8 +316,26 @@ Optional<ConformancePair> ModuleFile::maybeReadConformance(Type conformingType){
|
||||
}
|
||||
|
||||
case INHERITED_PROTOCOL_CONFORMANCE: {
|
||||
// FIXME: Does this even make sense?
|
||||
llvm_unreachable("Not implemented");
|
||||
DeclID protoID;
|
||||
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.
|
||||
|
||||
@@ -194,6 +194,13 @@ private:
|
||||
/// If the record at the cursor is not a pattern, returns null.
|
||||
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.
|
||||
///
|
||||
/// The conformance will be newly-created; it's likely that it already exists
|
||||
|
||||
@@ -666,10 +666,10 @@ namespace decls_block {
|
||||
using SpecializedProtocolConformanceLayout = BCRecordLayout<
|
||||
SPECIALIZED_PROTOCOL_CONFORMANCE,
|
||||
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
|
||||
// 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
|
||||
// record that follows
|
||||
BCVBR<5>, // type mapping count
|
||||
@@ -681,7 +681,13 @@ namespace decls_block {
|
||||
|
||||
using InheritedProtocolConformanceLayout = BCRecordLayout<
|
||||
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<
|
||||
|
||||
@@ -190,6 +190,23 @@ namespace {
|
||||
/// Writes a list of generic 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.
|
||||
void writeConformance(const ProtocolDecl *protocol,
|
||||
const ProtocolConformance *conformance);
|
||||
@@ -707,6 +724,30 @@ bool Serializer::writeGenericParams(const GenericParamList *genericParams) {
|
||||
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
|
||||
Serializer::writeConformance(const ProtocolDecl *protocol,
|
||||
const ProtocolConformance *conformance) {
|
||||
@@ -786,23 +827,8 @@ Serializer::writeConformance(const ProtocolDecl *protocol,
|
||||
IdentifierID moduleOrTypeID;
|
||||
|
||||
bool appendGenericConformance
|
||||
= !isa<NormalProtocolConformance>(conf->getGenericConformance());
|
||||
if (appendGenericConformance) {
|
||||
// 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;
|
||||
}
|
||||
= encodeUnderlyingConformance(conf->getGenericConformance(),
|
||||
nominalID, moduleOrTypeID);
|
||||
|
||||
SpecializedProtocolConformanceLayout::emitRecord(Out, ScratchRecord,
|
||||
abbrCode,
|
||||
@@ -823,8 +849,25 @@ Serializer::writeConformance(const ProtocolDecl *protocol,
|
||||
}
|
||||
|
||||
case ProtocolConformanceKind::Inherited: {
|
||||
// FIXME: inherited conformance might not make sense?
|
||||
llvm_unreachable("Not implemented");
|
||||
auto conf = cast<InheritedProtocolConformance>(conformance);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user