Skip to content

Commit d6a2e30

Browse files
committed
[Serialization] Make requirement signature conformance loading lazy.
While the original commit was expected to have no effective impact, it turned out to actually solve some circularity issues after all involving protocols that inherit from other protocols. It should be a mild compile-time win as well in cases where the requirement signature is not needed at all. Test in subsequent commit. https://bugs.swift.org/browse/SR-5191 / rdar://problem/33804554 (cherry picked from commit 897effe)
1 parent 67c31bc commit d6a2e30

File tree

1 file changed

+53
-57
lines changed

1 file changed

+53
-57
lines changed

lib/Serialization/Deserialization.cpp

Lines changed: 53 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -647,59 +647,6 @@ NormalProtocolConformance *ModuleFile::readNormalConformance(
647647
dc->getAsNominalTypeOrNominalTypeExtensionContext()
648648
->registerProtocolConformance(conformance);
649649

650-
// Read requirement signature conformances.
651-
SmallVector<ProtocolConformanceRef, 4> reqConformances;
652-
653-
if (proto->isObjC() && getContext().LangOpts.EnableDeserializationRecovery) {
654-
// Don't crash if inherited protocols are added or removed.
655-
// This is limited to Objective-C protocols because we know their only
656-
// conformance requirements are on Self. This isn't actually a /safe/ change
657-
// even in Objective-C, but we mostly just don't want to crash.
658-
659-
// FIXME: DenseMap requires that its value type be default-constructible,
660-
// which ProtocolConformanceRef is not, hence the extra Optional.
661-
llvm::SmallDenseMap<ProtocolDecl *, Optional<ProtocolConformanceRef>, 16>
662-
conformancesForProtocols;
663-
while (conformanceCount--) {
664-
ProtocolConformanceRef nextConformance = readConformance(DeclTypeCursor);
665-
ProtocolDecl *confProto = nextConformance.getRequirement();
666-
conformancesForProtocols[confProto] = nextConformance;
667-
}
668-
669-
for (const auto &req : proto->getRequirementSignature()) {
670-
if (req.getKind() != RequirementKind::Conformance)
671-
continue;
672-
ProtocolDecl *proto =
673-
req.getSecondType()->castTo<ProtocolType>()->getDecl();
674-
auto iter = conformancesForProtocols.find(proto);
675-
if (iter != conformancesForProtocols.end()) {
676-
reqConformances.push_back(iter->getSecond().getValue());
677-
} else {
678-
// Put in an abstract conformance as a placeholder. This is a lie, but
679-
// there's not much better we can do. We're relying on the fact that
680-
// the rest of the compiler doesn't actually need to check the
681-
// conformance to an Objective-C protocol for anything important.
682-
// There are no associated types and we don't emit a Swift conformance
683-
// record.
684-
reqConformances.push_back(ProtocolConformanceRef(proto));
685-
}
686-
}
687-
688-
} else {
689-
auto isConformanceReq = [](const Requirement &req) {
690-
return req.getKind() == RequirementKind::Conformance;
691-
};
692-
if (conformanceCount != llvm::count_if(proto->getRequirementSignature(),
693-
isConformanceReq)) {
694-
fatal(llvm::make_error<llvm::StringError>(
695-
"serialized conformances do not match requirement signature",
696-
llvm::inconvertibleErrorCode()));
697-
}
698-
while (conformanceCount--)
699-
reqConformances.push_back(readConformance(DeclTypeCursor));
700-
}
701-
conformance->setSignatureConformances(reqConformances);
702-
703650
// If the conformance is complete, we're done.
704651
if (conformance->isComplete())
705652
return conformance;
@@ -4633,10 +4580,59 @@ void ModuleFile::finishNormalConformance(NormalProtocolConformance *conformance,
46334580
typeCount, conformanceCount,
46344581
rawIDs);
46354582

4636-
// Skip requirement signature conformances.
4637-
auto proto = conformance->getProtocol();
4638-
while (conformanceCount--)
4639-
(void)readConformance(DeclTypeCursor);
4583+
// Read requirement signature conformances.
4584+
const ProtocolDecl *proto = conformance->getProtocol();
4585+
SmallVector<ProtocolConformanceRef, 4> reqConformances;
4586+
4587+
if (proto->isObjC() && getContext().LangOpts.EnableDeserializationRecovery) {
4588+
// Don't crash if inherited protocols are added or removed.
4589+
// This is limited to Objective-C protocols because we know their only
4590+
// conformance requirements are on Self. This isn't actually a /safe/ change
4591+
// even in Objective-C, but we mostly just don't want to crash.
4592+
4593+
// FIXME: DenseMap requires that its value type be default-constructible,
4594+
// which ProtocolConformanceRef is not, hence the extra Optional.
4595+
llvm::SmallDenseMap<ProtocolDecl *, Optional<ProtocolConformanceRef>, 16>
4596+
conformancesForProtocols;
4597+
while (conformanceCount--) {
4598+
ProtocolConformanceRef nextConformance = readConformance(DeclTypeCursor);
4599+
ProtocolDecl *confProto = nextConformance.getRequirement();
4600+
conformancesForProtocols[confProto] = nextConformance;
4601+
}
4602+
4603+
for (const auto &req : proto->getRequirementSignature()) {
4604+
if (req.getKind() != RequirementKind::Conformance)
4605+
continue;
4606+
ProtocolDecl *proto =
4607+
req.getSecondType()->castTo<ProtocolType>()->getDecl();
4608+
auto iter = conformancesForProtocols.find(proto);
4609+
if (iter != conformancesForProtocols.end()) {
4610+
reqConformances.push_back(iter->getSecond().getValue());
4611+
} else {
4612+
// Put in an abstract conformance as a placeholder. This is a lie, but
4613+
// there's not much better we can do. We're relying on the fact that
4614+
// the rest of the compiler doesn't actually need to check the
4615+
// conformance to an Objective-C protocol for anything important.
4616+
// There are no associated types and we don't emit a Swift conformance
4617+
// record.
4618+
reqConformances.push_back(ProtocolConformanceRef(proto));
4619+
}
4620+
}
4621+
4622+
} else {
4623+
auto isConformanceReq = [](const Requirement &req) {
4624+
return req.getKind() == RequirementKind::Conformance;
4625+
};
4626+
if (conformanceCount != llvm::count_if(proto->getRequirementSignature(),
4627+
isConformanceReq)) {
4628+
fatal(llvm::make_error<llvm::StringError>(
4629+
"serialized conformances do not match requirement signature",
4630+
llvm::inconvertibleErrorCode()));
4631+
}
4632+
while (conformanceCount--)
4633+
reqConformances.push_back(readConformance(DeclTypeCursor));
4634+
}
4635+
conformance->setSignatureConformances(reqConformances);
46404636

46414637
ArrayRef<uint64_t>::iterator rawIDIter = rawIDs.begin();
46424638

0 commit comments

Comments
 (0)