Skip to content

Commit b5511bd

Browse files
committed
[Serialization] (De-)serialize witnesses completely.
The witnesses in a NormalProtocolConformance have never been completely serialized, because their substitutions involved a weird mix of archetypes that blew up the deserialization code. So, only the witness declarations themselves got serialized. Many clients (the type checker, SourceKit, etc.) didn't need the extra information, but some clients (e.g., the SIL optimizers) would end up recomputing this information. Ick. Now, serialize the complete Witness structure along with the AST, including information about the synthetic environment, complete substitutions, etc. This should obsolete some redundant code paths in the SIL optimization infrastructure. This (de-)serialization code takes a new-ish approach to serializing the synthetic environment in that it avoids serializing any archetypes. Rather, it maps everything back to interface types during serialization, and deserialization forms a new generic environment (with new archetypes!) on-the-fly, mapping deserialized types back into that environment (and to those archetypes). This way, we don't have to maintain identity of archetypes in the deserialization code, and might get some better re-use of the archetypes. More of rdar://problem/24079818.
1 parent 1b9946b commit b5511bd

File tree

9 files changed

+240
-49
lines changed

9 files changed

+240
-49
lines changed

include/swift/AST/SubstitutionMap.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ class SubstitutionMap {
5656
return subMap;
5757
}
5858

59+
/// Retrieve the conformances for the given type.
60+
ArrayRef<ProtocolConformanceRef> getConformances(CanType type) const;
61+
5962
void addSubstitution(CanType type, Type replacement);
6063

6164
void addConformances(CanType type, ArrayRef<ProtocolConformanceRef> conformances);

include/swift/AST/Witness.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ class ValueDecl;
8181
/// environment are those of the context of the protocol conformance (\c U
8282
/// and \c V, in the example above) and the innermost generic parameters are
8383
/// those of the generic requirement (\c T, in the example above). The
84-
/// \c Witness class contains this syntheetic environment (both its generic
84+
/// \c Witness class contains this synthetic environment (both its generic
8585
/// signature and a generic environment providing archetypes), a substitution
8686
/// map that allows one to map the interface types of the requirement into
8787
/// the interface types of the synthetic domain, and the set of substitutions

include/swift/Serialization/ModuleFile.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -710,10 +710,14 @@ class ModuleFile : public LazyMemberLoader {
710710
/// Reads a substitution record from \c DeclTypeCursor.
711711
///
712712
/// If the record at the cursor is not a substitution, returns None.
713-
Optional<Substitution> maybeReadSubstitution(llvm::BitstreamCursor &Cursor);
713+
Optional<Substitution> maybeReadSubstitution(llvm::BitstreamCursor &Cursor,
714+
GenericEnvironment *genericEnv =
715+
nullptr);
714716

715717
/// Recursively reads a protocol conformance from the given cursor.
716-
ProtocolConformanceRef readConformance(llvm::BitstreamCursor &Cursor);
718+
ProtocolConformanceRef readConformance(llvm::BitstreamCursor &Cursor,
719+
GenericEnvironment *genericEnv =
720+
nullptr);
717721

718722
/// Read the given normal conformance from the current module file.
719723
NormalProtocolConformance *

include/swift/Serialization/ModuleFormat.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ const uint16_t VERSION_MAJOR = 0;
5454
/// in source control, you should also update the comment to briefly
5555
/// describe what change you made. The content of this comment isn't important;
5656
/// it just ensures a conflict if two people change the module format.
57-
const uint16_t VERSION_MINOR = 280; // Last change: function qualified ownership
57+
const uint16_t VERSION_MINOR = 281; // Last change: complete witnesses
5858

5959
using DeclID = PointerEmbeddedInt<unsigned, 31>;
6060
using DeclIDField = BCFixed<31>;

lib/AST/ASTVerifier.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1893,7 +1893,7 @@ struct ASTNodeBase {};
18931893
}
18941894

18951895
// Check the witness substitutions.
1896-
auto witness = normal->getWitness(req, nullptr);
1896+
const auto &witness = normal->getWitness(req, nullptr);
18971897

18981898
if (witness.requiresSubstitution()) {
18991899
GenericEnv.push_back(witness.getSyntheticEnvironment());

lib/AST/SubstitutionMap.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,13 @@ addConformances(CanType type, ArrayRef<ProtocolConformanceRef> conformances) {
106106
(void) result;
107107
}
108108

109+
ArrayRef<ProtocolConformanceRef> SubstitutionMap::
110+
getConformances(CanType type) const {
111+
auto known = conformanceMap.find(type.getPointer());
112+
if (known == conformanceMap.end()) return { };
113+
return known->second;
114+
}
115+
109116
void SubstitutionMap::
110117
addParent(CanType type, CanType parent, AssociatedTypeDecl *assocType) {
111118
assert(type && parent && assocType);

lib/Serialization/Deserialization.cpp

Lines changed: 103 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -450,7 +450,9 @@ Pattern *ModuleFile::maybeReadPattern() {
450450
}
451451
}
452452

453-
ProtocolConformanceRef ModuleFile::readConformance(llvm::BitstreamCursor &Cursor){
453+
ProtocolConformanceRef ModuleFile::readConformance(
454+
llvm::BitstreamCursor &Cursor,
455+
GenericEnvironment *genericEnv) {
454456
using namespace decls_block;
455457

456458
SmallVector<uint64_t, 16> scratch;
@@ -475,6 +477,10 @@ ProtocolConformanceRef ModuleFile::readConformance(llvm::BitstreamCursor &Cursor
475477

476478
ASTContext &ctx = getContext();
477479
Type conformingType = getType(conformingTypeID);
480+
if (genericEnv) {
481+
conformingType = genericEnv->mapTypeIntoContext(getAssociatedModule(),
482+
conformingType);
483+
}
478484

479485
PrettyStackTraceType trace(getAssociatedModule()->getASTContext(),
480486
"reading specialized conformance for",
@@ -483,12 +489,13 @@ ProtocolConformanceRef ModuleFile::readConformance(llvm::BitstreamCursor &Cursor
483489
// Read the substitutions.
484490
SmallVector<Substitution, 4> substitutions;
485491
while (numSubstitutions--) {
486-
auto sub = maybeReadSubstitution(Cursor);
492+
auto sub = maybeReadSubstitution(Cursor, genericEnv);
487493
assert(sub.hasValue() && "Missing substitution?");
488494
substitutions.push_back(*sub);
489495
}
490496

491-
ProtocolConformanceRef genericConformance = readConformance(Cursor);
497+
ProtocolConformanceRef genericConformance =
498+
readConformance(Cursor, genericEnv);
492499
PrettyStackTraceDecl traceTo("... to", genericConformance.getRequirement());
493500

494501
assert(genericConformance.isConcrete() && "Abstract generic conformance?");
@@ -505,11 +512,17 @@ ProtocolConformanceRef ModuleFile::readConformance(llvm::BitstreamCursor &Cursor
505512

506513
ASTContext &ctx = getContext();
507514
Type conformingType = getType(conformingTypeID);
515+
if (genericEnv) {
516+
conformingType = genericEnv->mapTypeIntoContext(getAssociatedModule(),
517+
conformingType);
518+
}
519+
508520
PrettyStackTraceType trace(getAssociatedModule()->getASTContext(),
509521
"reading inherited conformance for",
510522
conformingType);
511523

512-
ProtocolConformanceRef inheritedConformance = readConformance(Cursor);
524+
ProtocolConformanceRef inheritedConformance =
525+
readConformance(Cursor, genericEnv);
513526
PrettyStackTraceDecl traceTo("... to",
514527
inheritedConformance.getRequirement());
515528

@@ -541,8 +554,7 @@ ProtocolConformanceRef ModuleFile::readConformance(llvm::BitstreamCursor &Cursor
541554
auto module = getModule(moduleID);
542555

543556
SmallVector<ProtocolConformance *, 2> conformances;
544-
nominal->lookupConformance(module, proto,
545-
conformances);
557+
nominal->lookupConformance(module, proto, conformances);
546558
PrettyStackTraceModuleFile traceMsg(
547559
"If you're seeing a crash here, check that your SDK and dependencies "
548560
"are at least as new as the versions used to build", this);
@@ -641,7 +653,8 @@ NormalProtocolConformance *ModuleFile::readNormalConformance(
641653
}
642654

643655
Optional<Substitution>
644-
ModuleFile::maybeReadSubstitution(llvm::BitstreamCursor &cursor) {
656+
ModuleFile::maybeReadSubstitution(llvm::BitstreamCursor &cursor,
657+
GenericEnvironment *genericEnv) {
645658
BCOffsetRAII lastRecordOffset(cursor);
646659

647660
auto entry = cursor.advance(AF_DontPopBlockAtEnd);
@@ -661,6 +674,10 @@ ModuleFile::maybeReadSubstitution(llvm::BitstreamCursor &cursor) {
661674
numConformances);
662675

663676
auto replacementTy = getType(replacementID);
677+
if (genericEnv) {
678+
replacementTy = genericEnv->mapTypeIntoContext(getAssociatedModule(),
679+
replacementTy);
680+
}
664681

665682
SmallVector<ProtocolConformanceRef, 4> conformanceBuf;
666683
while (numConformances--) {
@@ -4206,17 +4223,85 @@ void ModuleFile::finishNormalConformance(NormalProtocolConformance *conformance,
42064223
ASTContext &ctx = getContext();
42074224
ArrayRef<uint64_t>::iterator rawIDIter = rawIDs.begin();
42084225

4209-
WitnessMap witnesses;
42104226
while (valueCount--) {
4211-
auto first = cast<ValueDecl>(getDecl(*rawIDIter++));
4212-
auto second = cast_or_null<ValueDecl>(getDecl(*rawIDIter++));
4213-
assert(second || first->getAttrs().hasAttribute<OptionalAttr>() ||
4214-
first->getAttrs().isUnavailable(ctx));
4215-
(void) ctx;
4216-
if (second)
4217-
witnesses.insert(std::make_pair(first, second));
4218-
else
4219-
witnesses.insert(std::make_pair(first, Witness()));
4227+
auto req = cast<ValueDecl>(getDecl(*rawIDIter++));
4228+
auto witness = cast_or_null<ValueDecl>(getDecl(*rawIDIter++));
4229+
assert(witness ||
4230+
req->getAttrs().hasAttribute<OptionalAttr>() ||
4231+
req->getAttrs().isUnavailable(ctx));
4232+
if (!witness) {
4233+
conformance->setWitness(req, Witness());
4234+
continue;
4235+
}
4236+
4237+
// Generic signature and environment.
4238+
GenericSignature *syntheticSig = nullptr;
4239+
GenericEnvironment *syntheticEnv = nullptr;
4240+
if (unsigned numGenericParams = *rawIDIter++) {
4241+
// Generic parameters.
4242+
SmallVector<GenericTypeParamType *, 2> genericParams;
4243+
while (numGenericParams--) {
4244+
genericParams.push_back(
4245+
getType(*rawIDIter++)->castTo<GenericTypeParamType>());
4246+
}
4247+
4248+
// Generic requirements.
4249+
SmallVector<Requirement, 4> requirements;
4250+
readGenericRequirements(requirements);
4251+
4252+
// Form the generic signature for the synthetic environment.
4253+
syntheticSig = GenericSignature::get(genericParams, requirements);
4254+
4255+
// Create an archetype builder, which will help us create the
4256+
// synthetic environment.
4257+
ArchetypeBuilder builder(*getAssociatedModule(), ctx.Diags);
4258+
builder.addGenericSignature(syntheticSig, nullptr);
4259+
builder.finalize(SourceLoc());
4260+
syntheticEnv = builder.getGenericEnvironment();
4261+
}
4262+
4263+
// Requirement -> synthetic map.
4264+
SubstitutionMap reqToSyntheticMap;
4265+
bool hasReqToSyntheticMap = false;
4266+
if (unsigned numEntries = *rawIDIter++) {
4267+
hasReqToSyntheticMap = true;
4268+
while (numEntries--) {
4269+
auto first = getType(*rawIDIter++);
4270+
auto second = getType(*rawIDIter++);
4271+
reqToSyntheticMap.addSubstitution(first->getCanonicalType(), second);
4272+
4273+
if (unsigned numConformances = *rawIDIter++) {
4274+
SmallVector<ProtocolConformanceRef, 2> conformances;
4275+
while (numConformances--) {
4276+
conformances.push_back(readConformance(DeclTypeCursor));
4277+
}
4278+
reqToSyntheticMap.addConformances(first->getCanonicalType(),
4279+
ctx.AllocateCopy(conformances));
4280+
}
4281+
}
4282+
}
4283+
4284+
// Witness substitutions.
4285+
SmallVector<Substitution, 4> witnessSubstitutions;
4286+
if (unsigned numWitnessSubstitutions = *rawIDIter++) {
4287+
while (numWitnessSubstitutions--) {
4288+
auto sub = maybeReadSubstitution(DeclTypeCursor, syntheticEnv);
4289+
witnessSubstitutions.push_back(*sub);
4290+
}
4291+
}
4292+
4293+
// Handle simple witnesses.
4294+
if (witnessSubstitutions.empty() && !syntheticSig && !syntheticEnv &&
4295+
!hasReqToSyntheticMap) {
4296+
conformance->setWitness(req, Witness(witness));
4297+
continue;
4298+
}
4299+
4300+
// Set the witness.
4301+
conformance->setWitness(req,
4302+
Witness(witness, witnessSubstitutions,
4303+
syntheticSig, syntheticEnv,
4304+
reqToSyntheticMap));
42204305
}
42214306
assert(rawIDIter <= rawIDs.end() && "read too much");
42224307

@@ -4232,16 +4317,12 @@ void ModuleFile::finishNormalConformance(NormalProtocolConformance *conformance,
42324317
}
42334318
assert(rawIDIter <= rawIDs.end() && "read too much");
42344319

4320+
42354321
// Set type witnesses.
42364322
for (auto typeWitness : typeWitnesses) {
42374323
conformance->setTypeWitness(typeWitness.first, typeWitness.second.first,
42384324
typeWitness.second.second);
42394325
}
4240-
4241-
// Set witnesses.
4242-
for (auto witness : witnesses) {
4243-
conformance->setWitness(witness.first, witness.second);
4244-
}
42454326
}
42464327

42474328
static Optional<ForeignErrorConvention::Kind>

0 commit comments

Comments
 (0)