Skip to content

[Serialization] (De-)serialize witnesses completely. #5589

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 2, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions include/swift/AST/SubstitutionMap.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ class SubstitutionMap {
return subMap;
}

/// Retrieve the conformances for the given type.
ArrayRef<ProtocolConformanceRef> getConformances(CanType type) const;

void addSubstitution(CanType type, Type replacement);

void addConformances(CanType type, ArrayRef<ProtocolConformanceRef> conformances);
Expand Down
2 changes: 1 addition & 1 deletion include/swift/AST/Witness.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ class ValueDecl;
/// environment are those of the context of the protocol conformance (\c U
/// and \c V, in the example above) and the innermost generic parameters are
/// those of the generic requirement (\c T, in the example above). The
/// \c Witness class contains this syntheetic environment (both its generic
/// \c Witness class contains this synthetic environment (both its generic
/// signature and a generic environment providing archetypes), a substitution
/// map that allows one to map the interface types of the requirement into
/// the interface types of the synthetic domain, and the set of substitutions
Expand Down
8 changes: 6 additions & 2 deletions include/swift/Serialization/ModuleFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -710,10 +710,14 @@ class ModuleFile : public LazyMemberLoader {
/// Reads a substitution record from \c DeclTypeCursor.
///
/// If the record at the cursor is not a substitution, returns None.
Optional<Substitution> maybeReadSubstitution(llvm::BitstreamCursor &Cursor);
Optional<Substitution> maybeReadSubstitution(llvm::BitstreamCursor &Cursor,
GenericEnvironment *genericEnv =
nullptr);

/// Recursively reads a protocol conformance from the given cursor.
ProtocolConformanceRef readConformance(llvm::BitstreamCursor &Cursor);
ProtocolConformanceRef readConformance(llvm::BitstreamCursor &Cursor,
GenericEnvironment *genericEnv =
nullptr);

/// Read the given normal conformance from the current module file.
NormalProtocolConformance *
Expand Down
2 changes: 1 addition & 1 deletion include/swift/Serialization/ModuleFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ const uint16_t VERSION_MAJOR = 0;
/// in source control, you should also update the comment to briefly
/// describe what change you made. The content of this comment isn't important;
/// it just ensures a conflict if two people change the module format.
const uint16_t VERSION_MINOR = 280; // Last change: function qualified ownership
const uint16_t VERSION_MINOR = 281; // Last change: complete witnesses

using DeclID = PointerEmbeddedInt<unsigned, 31>;
using DeclIDField = BCFixed<31>;
Expand Down
2 changes: 1 addition & 1 deletion lib/AST/ASTVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1893,7 +1893,7 @@ struct ASTNodeBase {};
}

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

if (witness.requiresSubstitution()) {
GenericEnv.push_back(witness.getSyntheticEnvironment());
Expand Down
7 changes: 7 additions & 0 deletions lib/AST/SubstitutionMap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,13 @@ addConformances(CanType type, ArrayRef<ProtocolConformanceRef> conformances) {
(void) result;
}

ArrayRef<ProtocolConformanceRef> SubstitutionMap::
getConformances(CanType type) const {
auto known = conformanceMap.find(type.getPointer());
if (known == conformanceMap.end()) return { };
return known->second;
}

void SubstitutionMap::
addParent(CanType type, CanType parent, AssociatedTypeDecl *assocType) {
assert(type && parent && assocType);
Expand Down
125 changes: 103 additions & 22 deletions lib/Serialization/Deserialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,9 @@ Pattern *ModuleFile::maybeReadPattern() {
}
}

ProtocolConformanceRef ModuleFile::readConformance(llvm::BitstreamCursor &Cursor){
ProtocolConformanceRef ModuleFile::readConformance(
llvm::BitstreamCursor &Cursor,
GenericEnvironment *genericEnv) {
using namespace decls_block;

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

ASTContext &ctx = getContext();
Type conformingType = getType(conformingTypeID);
if (genericEnv) {
conformingType = genericEnv->mapTypeIntoContext(getAssociatedModule(),
conformingType);
}

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

ProtocolConformanceRef genericConformance = readConformance(Cursor);
ProtocolConformanceRef genericConformance =
readConformance(Cursor, genericEnv);
PrettyStackTraceDecl traceTo("... to", genericConformance.getRequirement());

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

ASTContext &ctx = getContext();
Type conformingType = getType(conformingTypeID);
if (genericEnv) {
conformingType = genericEnv->mapTypeIntoContext(getAssociatedModule(),
conformingType);
}

PrettyStackTraceType trace(getAssociatedModule()->getASTContext(),
"reading inherited conformance for",
conformingType);

ProtocolConformanceRef inheritedConformance = readConformance(Cursor);
ProtocolConformanceRef inheritedConformance =
readConformance(Cursor, genericEnv);
PrettyStackTraceDecl traceTo("... to",
inheritedConformance.getRequirement());

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

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

Optional<Substitution>
ModuleFile::maybeReadSubstitution(llvm::BitstreamCursor &cursor) {
ModuleFile::maybeReadSubstitution(llvm::BitstreamCursor &cursor,
GenericEnvironment *genericEnv) {
BCOffsetRAII lastRecordOffset(cursor);

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

auto replacementTy = getType(replacementID);
if (genericEnv) {
replacementTy = genericEnv->mapTypeIntoContext(getAssociatedModule(),
replacementTy);
}

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

WitnessMap witnesses;
while (valueCount--) {
auto first = cast<ValueDecl>(getDecl(*rawIDIter++));
auto second = cast_or_null<ValueDecl>(getDecl(*rawIDIter++));
assert(second || first->getAttrs().hasAttribute<OptionalAttr>() ||
first->getAttrs().isUnavailable(ctx));
(void) ctx;
if (second)
witnesses.insert(std::make_pair(first, second));
else
witnesses.insert(std::make_pair(first, Witness()));
auto req = cast<ValueDecl>(getDecl(*rawIDIter++));
auto witness = cast_or_null<ValueDecl>(getDecl(*rawIDIter++));
assert(witness ||
req->getAttrs().hasAttribute<OptionalAttr>() ||
req->getAttrs().isUnavailable(ctx));
if (!witness) {
conformance->setWitness(req, Witness());
continue;
}

// Generic signature and environment.
GenericSignature *syntheticSig = nullptr;
GenericEnvironment *syntheticEnv = nullptr;
if (unsigned numGenericParams = *rawIDIter++) {
// Generic parameters.
SmallVector<GenericTypeParamType *, 2> genericParams;
while (numGenericParams--) {
genericParams.push_back(
getType(*rawIDIter++)->castTo<GenericTypeParamType>());
}

// Generic requirements.
SmallVector<Requirement, 4> requirements;
readGenericRequirements(requirements);

// Form the generic signature for the synthetic environment.
syntheticSig = GenericSignature::get(genericParams, requirements);

// Create an archetype builder, which will help us create the
// synthetic environment.
ArchetypeBuilder builder(*getAssociatedModule(), ctx.Diags);
builder.addGenericSignature(syntheticSig, nullptr);
builder.finalize(SourceLoc());
syntheticEnv = builder.getGenericEnvironment();
}

// Requirement -> synthetic map.
SubstitutionMap reqToSyntheticMap;
bool hasReqToSyntheticMap = false;
if (unsigned numEntries = *rawIDIter++) {
hasReqToSyntheticMap = true;
while (numEntries--) {
auto first = getType(*rawIDIter++);
auto second = getType(*rawIDIter++);
reqToSyntheticMap.addSubstitution(first->getCanonicalType(), second);

if (unsigned numConformances = *rawIDIter++) {
SmallVector<ProtocolConformanceRef, 2> conformances;
while (numConformances--) {
conformances.push_back(readConformance(DeclTypeCursor));
}
reqToSyntheticMap.addConformances(first->getCanonicalType(),
ctx.AllocateCopy(conformances));
}
}
}

// Witness substitutions.
SmallVector<Substitution, 4> witnessSubstitutions;
if (unsigned numWitnessSubstitutions = *rawIDIter++) {
while (numWitnessSubstitutions--) {
auto sub = maybeReadSubstitution(DeclTypeCursor, syntheticEnv);
witnessSubstitutions.push_back(*sub);
}
}

// Handle simple witnesses.
if (witnessSubstitutions.empty() && !syntheticSig && !syntheticEnv &&
!hasReqToSyntheticMap) {
conformance->setWitness(req, Witness(witness));
continue;
}

// Set the witness.
conformance->setWitness(req,
Witness(witness, witnessSubstitutions,
syntheticSig, syntheticEnv,
reqToSyntheticMap));
}
assert(rawIDIter <= rawIDs.end() && "read too much");

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


// Set type witnesses.
for (auto typeWitness : typeWitnesses) {
conformance->setTypeWitness(typeWitness.first, typeWitness.second.first,
typeWitness.second.second);
}

// Set witnesses.
for (auto witness : witnesses) {
conformance->setWitness(witness.first, witness.second);
}
}

static Optional<ForeignErrorConvention::Kind>
Expand Down
Loading