mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Store the conforming type within an abstract ProtocolConformanceRef
An "abstract" ProtocolConformanceRef is a conformance of a type parameter or archetype to a given protocol. Previously, we would only store the protocol requirement itself---but not track the actual conforming type, requiring clients of ProtocolConformanceRef to keep track of this information separately. Record the conforming type as part of an abstract ProtocolConformanceRef, so that clients will be able to recover it later. This is handled by a uniqued AbstractConformance structure, so that ProtocolConformanceRef itself stays one pointer. There remain a small number of places where we create an abstract ProtocolConformanceRef with a null type. We'll want to chip away at those and establish some stronger invariants on the abstract conformance in the future.
This commit is contained in:
@@ -787,6 +787,9 @@ public:
|
||||
|
||||
Expected<PackConformance *>
|
||||
read(ModuleFile::Serialized<PackConformance *> &entry);
|
||||
|
||||
Expected<AbstractConformance *>
|
||||
read(ModuleFile::Serialized<AbstractConformance *> &entry);
|
||||
};
|
||||
} // end namespace swift
|
||||
|
||||
@@ -1105,6 +1108,47 @@ ProtocolConformanceDeserializer::readNormalProtocolConformance(
|
||||
return conformance;
|
||||
}
|
||||
|
||||
Expected<AbstractConformance *>
|
||||
ProtocolConformanceDeserializer::read(
|
||||
ModuleFile::Serialized<AbstractConformance *> &conformanceEntry) {
|
||||
using namespace decls_block;
|
||||
|
||||
SmallVector<uint64_t, 16> scratch;
|
||||
|
||||
llvm::BitstreamEntry entry =
|
||||
MF.fatalIfUnexpected(MF.DeclTypeCursor.advance());
|
||||
|
||||
if (entry.Kind != llvm::BitstreamEntry::Record) {
|
||||
// We don't know how to serialize types represented by sub-blocks.
|
||||
return MF.diagnoseFatal();
|
||||
}
|
||||
|
||||
StringRef blobData;
|
||||
unsigned kind = MF.fatalIfUnexpected(
|
||||
MF.DeclTypeCursor.readRecord(entry.ID, scratch, &blobData));
|
||||
assert(blobData.empty());
|
||||
|
||||
if (kind != decls_block::ABSTRACT_CONFORMANCE)
|
||||
return MF.diagnoseFatal(llvm::make_error<InvalidRecordKindError>(kind));
|
||||
|
||||
TypeID conformingTypeID;
|
||||
DeclID protocolID;
|
||||
AbstractConformanceLayout::readRecord(scratch, conformingTypeID, protocolID);
|
||||
|
||||
auto conformingTypeOrError = MF.getTypeChecked(conformingTypeID);
|
||||
if (!conformingTypeOrError)
|
||||
return conformingTypeOrError.takeError();
|
||||
auto conformingType = conformingTypeOrError.get();
|
||||
|
||||
auto protocolOrError = MF.getDeclChecked(protocolID);
|
||||
if (!protocolOrError)
|
||||
return protocolOrError.takeError();
|
||||
auto *protocol = cast<ProtocolDecl>(protocolOrError.get());
|
||||
|
||||
return ProtocolConformanceRef::forAbstract(conformingType, protocol)
|
||||
.getAbstract();
|
||||
}
|
||||
|
||||
Expected<PackConformance*>
|
||||
ProtocolConformanceDeserializer::read(
|
||||
ModuleFile::Serialized<PackConformance *> &conformanceEntry) {
|
||||
@@ -1180,13 +1224,25 @@ ModuleFile::getConformanceChecked(ProtocolConformanceID conformanceID) {
|
||||
|
||||
switch (conformanceID & SerializedProtocolConformanceKind::Mask) {
|
||||
case SerializedProtocolConformanceKind::Abstract: {
|
||||
auto protocolID = conformanceID >> SerializedProtocolConformanceKind::Shift;
|
||||
auto maybeProtocol = getDeclChecked(protocolID);
|
||||
if (!maybeProtocol)
|
||||
return maybeProtocol.takeError();
|
||||
auto proto = cast<ProtocolDecl>(maybeProtocol.get());
|
||||
// FIXME: Passing an empty Type() here temporarily.
|
||||
return ProtocolConformanceRef::forAbstract(Type(), proto);
|
||||
auto conformanceIndex = (conformanceID >> SerializedProtocolConformanceKind::Shift) - 1;
|
||||
assert(conformanceIndex < AbstractConformances.size() &&
|
||||
"invalid abstract conformance ID");
|
||||
auto &conformanceOrOffset = AbstractConformances[conformanceIndex];
|
||||
if (!conformanceOrOffset.isComplete()) {
|
||||
BCOffsetRAII restoreOffset(DeclTypeCursor);
|
||||
if (auto error = diagnoseFatalIfNotSuccess(
|
||||
DeclTypeCursor.JumpToBit(conformanceOrOffset)))
|
||||
return std::move(error);
|
||||
|
||||
auto result =
|
||||
ProtocolConformanceDeserializer(*this).read(conformanceOrOffset);
|
||||
if (!result)
|
||||
return result.takeError();
|
||||
|
||||
conformanceOrOffset = result.get();
|
||||
}
|
||||
auto conformance = conformanceOrOffset.get();
|
||||
return ProtocolConformanceRef(conformance);
|
||||
}
|
||||
|
||||
case SerializedProtocolConformanceKind::Concrete: {
|
||||
|
||||
Reference in New Issue
Block a user