From fadebe02bbafef11fedeff0f211e936afc1408cd Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Fri, 13 Dec 2013 21:31:57 +0000 Subject: [PATCH] Stop using ProtocolConformance::getTypeWitnesses() almost everywhere. In doing so, make serialization more deterministic. It was depending on DenseMap ordering for both type and value witnesses. Now, serialize the witnesses in the declaration order of the requirements. Swift SVN r11267 --- lib/SILGen/SILGenDecl.cpp | 8 +-- lib/Sema/TypeCheckProtocol.cpp | 1 + lib/Serialization/Serialization.cpp | 96 ++++++++++++++++++++++------- 3 files changed, 76 insertions(+), 29 deletions(-) diff --git a/lib/SILGen/SILGenDecl.cpp b/lib/SILGen/SILGenDecl.cpp index f98104dac13..3d0088c7a5d 100644 --- a/lib/SILGen/SILGenDecl.cpp +++ b/lib/SILGen/SILGenDecl.cpp @@ -1829,12 +1829,8 @@ public: void visitAssociatedTypeDecl(AssociatedTypeDecl *td) { // Find the substitution info for the witness type. - auto foundWitness = Conformance->getTypeWitnesses().find(td); - assert(foundWitness != Conformance->getTypeWitnesses().end() - && "no witness for associated type requirement"); - - Substitution witness = foundWitness->second; - + const auto &witness = Conformance->getTypeWitness(td); + // Emit the record for the type itself. Entries.push_back(SILWitnessTable::AssociatedTypeWitness{td, witness.Replacement->getCanonicalType()}); diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index 2ad667424ce..a036296099d 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -967,6 +967,7 @@ checkConformsToProtocol(TypeChecker &TC, Type T, ProtocolDecl *Proto, // viable. if (matchWitness(TC, Proto, DC, Requirement, T, derived, TypeWitnesses).isViable()) { + Mapping[Requirement] = derived; numViable = 1; continue; } diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 99bcd94d072..82936c3a455 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -598,6 +598,42 @@ Serializer::encodeUnderlyingConformance(const ProtocolConformance *conformance, return append; } +namespace { + /// Apply the given function object to each value witness within the + /// given protocol conformance. + /// + /// The function object should accept a \c ValueDecl* for the requirement + /// followed by the \c ConcreteDeclRef for the witness. + template + void forEachValueWitness(const ProtocolConformance *conformance, F f) { + const ProtocolDecl *protocol = conformance->getProtocol(); + for (auto req : protocol->getMembers()) { + auto valueReq = dyn_cast(req); + if (!valueReq || isa(valueReq)) + continue; + + f(valueReq, conformance->getWitness(valueReq)); + } + } + + /// Apply the given function object to each type witness within the given + /// protocol conformance. + /// + /// The function object should accept an \c AssociatedTypeDecl* for the + /// requirement followed by the \c Substitution for the witness. + template + void forEachTypeWitness(const ProtocolConformance *conformance, F f) { + const ProtocolDecl *protocol = conformance->getProtocol(); + for (auto req : protocol->getMembers()) { + auto assocTypeReq = dyn_cast(req); + if (!assocTypeReq) + continue; + + f(assocTypeReq, conformance->getTypeWitness(assocTypeReq)); + } + } +} + void Serializer::writeConformance(const ProtocolDecl *protocol, const ProtocolConformance *conformance, @@ -627,18 +663,23 @@ Serializer::writeConformance(const ProtocolDecl *protocol, unsigned numValueWitnesses = 0; unsigned numTypeWitnesses = 0; unsigned numDefaultedDefinitions = 0; - for (auto valueMapping : conf->getWitnesses()) { - data.push_back(addDeclRef(valueMapping.first)); - data.push_back(addDeclRef(valueMapping.second.getDecl())); + forEachValueWitness(conformance, + [&](ValueDecl *req, ConcreteDeclRef witness) { + data.push_back(addDeclRef(req)); + data.push_back(addDeclRef(witness.getDecl())); // The substitution records are serialized later. - data.push_back(valueMapping.second.getSubstitutions().size()); + data.push_back(witness.getSubstitutions().size()); ++numValueWitnesses; - } - for (auto typeMapping : conf->getTypeWitnesses()) { - data.push_back(addDeclRef(typeMapping.first)); - // The substitution record is serialized later. - ++numTypeWitnesses; - } + }); + + forEachTypeWitness(conformance, + [&](AssociatedTypeDecl *assocType, + const Substitution &witness) { + data.push_back(addDeclRef(assocType)); + // The substitution record is serialized later. + ++numTypeWitnesses; + }); + for (auto defaulted : conf->getDefaultedDefinitions()) { data.push_back(addDeclRef(defaulted)); ++numDefaultedDefinitions; @@ -664,12 +705,15 @@ Serializer::writeConformance(const ProtocolDecl *protocol, } writeConformances(inheritedProtos, inheritedConformance, associatedDecl, abbrCodes); - for (auto valueMapping : conf->getWitnesses()) { - writeSubstitutions(valueMapping.second.getSubstitutions(), - abbrCodes); - } - for (auto typeMapping : conf->getTypeWitnesses()) - writeSubstitutions(typeMapping.second, abbrCodes); + forEachValueWitness(conformance, + [&](ValueDecl *req, ConcreteDeclRef witness) { + writeSubstitutions(witness.getSubstitutions(), abbrCodes); + }); + forEachTypeWitness(conformance, + [&](AssociatedTypeDecl *assocType, + const Substitution &witness) { + writeSubstitutions(witness, abbrCodes); + }); break; } @@ -678,11 +722,13 @@ Serializer::writeConformance(const ProtocolDecl *protocol, auto conf = cast(conformance); SmallVector data; unsigned numTypeWitnesses = 0; - for (auto typeMapping : conf->getTypeWitnesses()) { - data.push_back(addDeclRef(typeMapping.first)); - // The substitution record is serialized later. - ++numTypeWitnesses; - } + forEachTypeWitness(conf, + [&](AssociatedTypeDecl *assocType, + const Substitution &witness) { + data.push_back(addDeclRef(assocType)); + // The substitution record is serialized later. + ++numTypeWitnesses; + }); auto substitutions = conf->getGenericSubstitutions(); unsigned abbrCode = abbrCodes[SpecializedProtocolConformanceLayout::Code]; @@ -702,8 +748,12 @@ Serializer::writeConformance(const ProtocolDecl *protocol, substitutions.size(), data); writeSubstitutions(substitutions, abbrCodes); - for (auto typeMapping : conf->getTypeWitnesses()) - writeSubstitutions(typeMapping.second, abbrCodes); + + forEachTypeWitness(conformance, + [&](AssociatedTypeDecl *assocType, + const Substitution &witness) { + writeSubstitutions(witness, abbrCodes); + }); if (appendGenericConformance) { writeConformance(protocol, conf->getGenericConformance(), nullptr,