AST: Witness stores SubstitutionList instead of SubstitutionMap

This simplifies serialization and removes some calls of
SubstitutionMap::addSubstitution() and addConformance().
This commit is contained in:
Slava Pestov
2017-02-07 23:47:24 -08:00
parent e8bd2cb367
commit ec4a95be21
7 changed files with 55 additions and 84 deletions

View File

@@ -19,7 +19,7 @@
#define SWIFT_AST_WITNESS_H
#include "swift/AST/ConcreteDeclRef.h"
#include "swift/AST/SubstitutionMap.h"
#include "swift/AST/SubstitutionList.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/Support/Compiler.h"
@@ -93,7 +93,7 @@ class Witness {
/// the witness declaration from the synthetic environment.
ConcreteDeclRef declRef;
GenericEnvironment *syntheticEnvironment;
SubstitutionMap reqToSyntheticEnvMap;
SubstitutionList reqToSyntheticEnvSubs;
};
llvm::PointerUnion<ValueDecl *, StoredWitness *> storage;
@@ -117,11 +117,12 @@ public:
///
/// \param syntheticEnv The synthetic environment.
///
/// \param reqToSyntheticEnvMap The mapping from the interface types of the
/// \param reqToSyntheticEnvSubs The mapping from the interface types of the
/// requirement into the interface types of the synthetic environment.
Witness(ValueDecl *decl, SubstitutionList substitutions,
Witness(ValueDecl *decl,
SubstitutionList substitutions,
GenericEnvironment *syntheticEnv,
SubstitutionMap reqToSyntheticEnvMap);
SubstitutionList reqToSyntheticEnvSubs);
/// Retrieve the witness declaration reference, which includes the
/// substitutions needed to use the witness from the synthetic environment
@@ -166,9 +167,9 @@ public:
/// Retrieve the substitution map that maps the interface types of the
/// requirement to the interface types of the synthetic environment.
const SubstitutionMap &getRequirementToSyntheticMap() const {
SubstitutionList getRequirementToSyntheticSubs() const {
assert(requiresSubstitution() && "No substitutions required for witness");
return storage.get<StoredWitness *>()->reqToSyntheticEnvMap;
return storage.get<StoredWitness *>()->reqToSyntheticEnvSubs;
}
LLVM_ATTRIBUTE_DEPRECATED(

View File

@@ -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 = 313; // Last change: generic environments
const uint16_t VERSION_MINOR = 314; // Last change: change synthetic substitution serialization
using DeclID = PointerEmbeddedInt<unsigned, 31>;
using DeclIDField = BCFixed<31>;

View File

@@ -32,13 +32,14 @@ using namespace swift;
Witness::Witness(ValueDecl *decl, SubstitutionList substitutions,
GenericEnvironment *syntheticEnv,
SubstitutionMap reqToSynthesizedEnvMap) {
SubstitutionList reqToSynthesizedEnvSubs) {
auto &ctx = decl->getASTContext();
auto declRef = ConcreteDeclRef(ctx, decl, substitutions);
auto storedMem = ctx.Allocate(sizeof(StoredWitness), alignof(StoredWitness));
auto stored = new (storedMem)
StoredWitness{declRef, syntheticEnv, std::move(reqToSynthesizedEnvMap)};
StoredWitness{declRef, syntheticEnv,
ctx.AllocateCopy(reqToSynthesizedEnvSubs)};
ctx.addDestructorCleanup(*stored);
storage = stored;

View File

@@ -1799,10 +1799,11 @@ SILGenModule::emitProtocolWitness(ProtocolConformance *conformance,
genericEnv = witness.getSyntheticEnvironment();
witnessSubs = witness.getSubstitutions();
const SubstitutionMap &reqtSubs
= witness.getRequirementToSyntheticMap();
auto input = reqtOrigTy->getInput().subst(reqtSubs)->getCanonicalType();
auto result = reqtOrigTy->getResult().subst(reqtSubs)->getCanonicalType();
auto reqtSubs = witness.getRequirementToSyntheticSubs();
auto reqtSubMap = reqtOrigTy->getGenericSignature()
->getSubstitutionMap(reqtSubs);
auto input = reqtOrigTy->getInput().subst(reqtSubMap);
auto result = reqtOrigTy->getResult().subst(reqtSubMap);
if (genericEnv) {
auto *genericSig = genericEnv->getGenericSignature();
@@ -1811,8 +1812,10 @@ SILGenModule::emitProtocolWitness(ProtocolConformance *conformance,
reqtOrigTy->getExtInfo())
->getCanonicalType());
} else {
reqtSubstTy = CanFunctionType::get(input, result,
reqtOrigTy->getExtInfo());
reqtSubstTy = cast<FunctionType>(
FunctionType::get(input, result,
reqtOrigTy->getExtInfo())
->getCanonicalType());
}
} else {
genericEnv = witnessRef.getDecl()->getInnermostDeclContext()

View File

@@ -60,8 +60,8 @@ namespace {
class RequirementEnvironment {
GenericSignature *syntheticSignature = nullptr;
GenericEnvironment *syntheticEnvironment = nullptr;
GenericSignature *reqSig = nullptr;
SubstitutionMap reqToSyntheticEnvMap;
bool valid = true;
public:
/// Create a new environment for matching the given requirement within a
@@ -82,27 +82,19 @@ namespace {
/// Retrieve the synthetic generic environment.
GenericEnvironment *getSyntheticEnvironment() const {
assert(valid && "Already stole from this generic environment");
return syntheticEnvironment;
}
/// Retrieve the generic signature of the requirement.
const GenericSignature *getRequirementSignature() const {
return reqSig;
}
/// Retrieve the substitution map that maps the interface types of the
/// requirement to the interface types of the synthetic environment.
const SubstitutionMap &getRequirementToSyntheticMap() const {
assert(valid && "Already stole from this generic environment");
return reqToSyntheticEnvMap;
}
/// Take the substitution map that maps the interface types of the
/// requirement to the interface types of the synthetic environment.
///
/// This can only be done once, and makes the requirement environment
/// invalid.
SubstitutionMap &&takeRequirementToSyntheticMap() {
assert(valid && "Already stole from this generic environment");
valid = false;
return std::move(reqToSyntheticEnvMap);
}
};
class WitnessChecker {
@@ -419,11 +411,13 @@ namespace {
swift::Witness getWitness(ASTContext &ctx,
RequirementEnvironment &&reqEnvironment) const {
auto environment = reqEnvironment.getSyntheticEnvironment();
auto map = reqEnvironment.takeRequirementToSyntheticMap();
SmallVector<Substitution, 2> syntheticSubs;
auto syntheticEnv = reqEnvironment.getSyntheticEnvironment();
reqEnvironment.getRequirementSignature()->getSubstitutions(
reqEnvironment.getRequirementToSyntheticMap(),
syntheticSubs);
return swift::Witness(this->Witness, WitnessSubstitutions,
environment,
map);
syntheticEnv, syntheticSubs);
}
/// Classify the provided optionality issues for use in diagnostics.
@@ -981,6 +975,10 @@ RequirementEnvironment::RequirementEnvironment(
DeclContext *conformanceDC,
ValueDecl *req,
ProtocolConformance *conformance) {
auto reqDC = req->getInnermostDeclContext();
reqSig = reqDC->getGenericSignatureOfContext();
ASTContext &ctx = tc.Context;
auto proto = cast<ProtocolDecl>(req->getDeclContext());
@@ -1046,8 +1044,6 @@ RequirementEnvironment::RequirementEnvironment(
// Add the generic signature of the requirement, substituting our concrete
// type for 'Self'. We don't need the 'Self' requirement or parameter.
auto reqDC = req->getInnermostDeclContext();
auto reqSig = reqDC->getGenericSignatureOfContext();
auto reqEnv = reqDC->getGenericEnvironmentOfContext();
// First, add the generic parameters from the requirement.
@@ -1187,9 +1183,10 @@ matchWitness(TypeChecker &tc,
// the required type and the witness type.
cs.emplace(tc, dc, ConstraintSystemOptions());
auto &reqSubs = reqEnvironment.getRequirementToSyntheticMap();
auto reqGenericEnv = reqEnvironment.getSyntheticEnvironment();
Type selfTy = proto->getSelfInterfaceType().subst(reqSubs);
auto &reqSubMap = reqEnvironment.getRequirementToSyntheticMap();
Type selfTy = proto->getSelfInterfaceType().subst(reqSubMap);
if (reqGenericEnv)
selfTy = reqGenericEnv->mapTypeIntoContext(selfTy);
@@ -1211,7 +1208,7 @@ matchWitness(TypeChecker &tc,
// For any type parameters we replaced in the witness, map them
// to the corresponding archetypes in the witness's context.
for (const auto &replacement : reqReplacements) {
auto replacedInReq = replacement.first.subst(reqSubs);
auto replacedInReq = replacement.first.subst(reqSubMap);
// If substitution failed, skip the requirement. This only occurs in
// invalid code.

View File

@@ -4362,8 +4362,7 @@ void ModuleFile::finishNormalConformance(NormalProtocolConformance *conformance,
GenericEnvironment *syntheticEnv = nullptr;
// Requirement -> synthetic map.
SubstitutionMap reqToSyntheticMap;
bool hasReqToSyntheticMap = false;
SmallVector<Substitution, 4> reqToSyntheticSubs;
if (unsigned numGenericParams = *rawIDIter++) {
// Generic parameters of the synthetic environment.
SmallVector<GenericTypeParamType *, 2> genericParams;
@@ -4383,21 +4382,11 @@ void ModuleFile::finishNormalConformance(NormalProtocolConformance *conformance,
syntheticEnv =
syntheticSig->createGenericEnvironment(*getAssociatedModule());
// Requirement -> synthetic map.
hasReqToSyntheticMap = true;
auto reqSignature =
req->getInnermostDeclContext()->getGenericSignatureOfContext();
for (auto reqGP : reqSignature->getGenericParams()) {
auto canonicalGP =
cast<GenericTypeParamType>(reqGP->getCanonicalType());
auto concreteTy = getType(*rawIDIter++);
reqToSyntheticMap.addSubstitution(canonicalGP, concreteTy);
if (unsigned numConformances = *rawIDIter++) {
while (numConformances--) {
reqToSyntheticMap.addConformance(
canonicalGP, readConformance(DeclTypeCursor));
}
// Requirement -> synthetic substitutions.
if (unsigned numReqSubstitutions = *rawIDIter++) {
while (numReqSubstitutions--) {
auto sub = maybeReadSubstitution(DeclTypeCursor, nullptr);
reqToSyntheticSubs.push_back(*sub);
}
}
}
@@ -4413,14 +4402,14 @@ void ModuleFile::finishNormalConformance(NormalProtocolConformance *conformance,
// Handle simple witnesses.
if (witnessSubstitutions.empty() && !syntheticSig && !syntheticEnv &&
!hasReqToSyntheticMap) {
reqToSyntheticSubs.empty()) {
conformance->setWitness(req, Witness(witness));
continue;
}
// Set the witness.
conformance->setWitness(req, Witness(witness, witnessSubstitutions,
syntheticEnv, reqToSyntheticMap));
syntheticEnv, reqToSyntheticSubs));
}
assert(rawIDIter <= rawIDs.end() && "read too much");

View File

@@ -1212,20 +1212,8 @@ void Serializer::writeNormalConformance(
for (auto gp : genericSig->getGenericParams())
data.push_back(addTypeRef(gp));
// Mapping from the requirement's interface types to the interface
// types of the synthetic environment.
auto reqSignature =
req->getInnermostDeclContext()->getGenericSignatureOfContext();
const auto &reqToSyntheticMap = witness.getRequirementToSyntheticMap();
for (auto reqGP : reqSignature->getGenericParams()) {
auto canonicalGP =
cast<GenericTypeParamType>(reqGP->getCanonicalType());
data.push_back(
addTypeRef(Type(canonicalGP).subst(reqToSyntheticMap)));
auto conformances = reqToSyntheticMap.getConformances(canonicalGP);
data.push_back(conformances.size());
// Conformances come at the end.
}
auto reqToSyntheticSubs = witness.getRequirementToSyntheticSubs();
data.push_back(reqToSyntheticSubs.size());
// Requirements come at the end.
} else {
@@ -1278,18 +1266,10 @@ void Serializer::writeNormalConformance(
writeGenericRequirements(genericSig->getRequirements(),
DeclTypeAbbrCodes);
// Write conformances for the requirement-to-synthetic environment map.
auto reqSignature =
req->getInnermostDeclContext()->getGenericSignatureOfContext();
const auto &reqToSyntheticMap = witness.getRequirementToSyntheticMap();
for (auto reqGP : reqSignature->getGenericParams()) {
auto canonicalGP =
cast<GenericTypeParamType>(reqGP->getCanonicalType());
auto conformances = reqToSyntheticMap.getConformances(canonicalGP);
for (auto conformance : conformances) {
writeConformance(conformance, DeclTypeAbbrCodes);
}
}
// Write requirement-to-synthetic substitutions.
writeSubstitutions(witness.getRequirementToSyntheticSubs(),
DeclTypeAbbrCodes,
nullptr);
}
// Write the witness substitutions.