mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
AST: Witness stores SubstitutionList instead of SubstitutionMap
This simplifies serialization and removes some calls of SubstitutionMap::addSubstitution() and addConformance().
This commit is contained in:
@@ -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(
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user