Skip to content

Commit 39612dc

Browse files
authored
Merge pull request #16249 from DougGregor/flatten-substitution-map
2 parents 8459167 + cdff742 commit 39612dc

File tree

6 files changed

+358
-229
lines changed

6 files changed

+358
-229
lines changed

include/swift/AST/GenericSignature.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,17 @@ class alignas(1 << TypeAlignInBits) GenericSignature final
223223
});
224224
}
225225

226+
/// Compute the number of conformance requirements in this signature.
227+
unsigned getNumConformanceRequirements() const {
228+
unsigned result = 0;
229+
for (const auto &req : getRequirements()) {
230+
if (req.getKind() == RequirementKind::Conformance)
231+
++result;
232+
}
233+
234+
return result;
235+
}
236+
226237
/// Return the size of a SubstitutionList built from this signature.
227238
///
228239
/// Don't add new calls of this -- the representation of SubstitutionList

include/swift/AST/SubstitutionMap.h

Lines changed: 147 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -12,37 +12,26 @@
1212
//
1313
// This file defines the SubstitutionMap class.
1414
//
15-
// This is a data structure type describing the mapping of abstract types to
16-
// replacement types, together with associated conformances to use for deriving
17-
// nested types.
18-
//
19-
// Depending on how the SubstitutionMap is constructed, the abstract types are
20-
// either archetypes or interface types. Care must be exercised to only look up
21-
// one or the other.
22-
//
23-
// SubstitutionMaps are constructed by calling the getSubstitutionMap() method
24-
// on a GenericSignature or GenericEnvironment.
25-
//
2615
//===----------------------------------------------------------------------===//
2716

2817
#ifndef SWIFT_AST_SUBSTITUTION_MAP_H
2918
#define SWIFT_AST_SUBSTITUTION_MAP_H
3019

20+
#include "swift/AST/GenericSignature.h"
3121
#include "swift/AST/ProtocolConformanceRef.h"
22+
#include "swift/AST/SubstitutionList.h"
3223
#include "swift/AST/Type.h"
3324
#include "llvm/ADT/ArrayRef.h"
34-
#include "llvm/ADT/DenseMap.h"
25+
#include "llvm/ADT/FoldingSet.h"
3526
#include "llvm/ADT/Optional.h"
36-
#include "llvm/ADT/SmallPtrSet.h"
37-
#include "llvm/ADT/SmallVector.h"
27+
#include "llvm/Support/TrailingObjects.h"
3828

3929
namespace llvm {
4030
class FoldingSetNodeID;
4131
}
4232

4333
namespace swift {
4434

45-
class GenericSignature;
4635
class GenericEnvironment;
4736
class SubstitutableType;
4837
typedef CanTypeWrapper<GenericTypeParamType> CanGenericTypeParamType;
@@ -55,48 +44,165 @@ enum class CombineSubstitutionMaps {
5544
AtIndex
5645
};
5746

47+
/// SubstitutionMap is a data structure type that describes the mapping of
48+
/// abstract types to replacement types, together with associated conformances
49+
/// to use for deriving nested types and conformances.
50+
///
51+
/// Depending on how the SubstitutionMap is constructed, the abstract types are
52+
/// either archetypes or interface types. Care must be exercised to only look
53+
/// up one or the other.
54+
///
55+
/// SubstitutionMaps are constructed by calling the getSubstitutionMap() method
56+
/// on a GenericSignature or (equivalently) by calling one of the static
57+
/// \c SubstitutionMap::get() methods.
5858
class SubstitutionMap {
59-
/// The generic signature for which we are performing substitutions.
60-
GenericSignature *genericSig;
61-
62-
/// The replacement types for the generic type parameters.
63-
std::unique_ptr<Type[]> replacementTypes;
59+
public:
60+
/// Stored data for a substitution map, which uses tail allocation for the
61+
/// replacement types and conformances.
62+
class Storage final
63+
: public llvm::FoldingSetNode,
64+
llvm::TrailingObjects<Storage, Type, ProtocolConformanceRef>
65+
{
66+
friend TrailingObjects;
67+
68+
/// The generic signature for which we are performing substitutions.
69+
GenericSignature * const genericSig;
70+
71+
/// The number of conformance requirements, cached to avoid constantly
72+
/// recomputing it on conformance-buffer access.
73+
const unsigned numConformanceRequirements;
74+
75+
Storage() = delete;
76+
77+
Storage(GenericSignature *genericSig,
78+
ArrayRef<Type> replacementTypes,
79+
ArrayRef<ProtocolConformanceRef> conformances);
80+
81+
private:
82+
unsigned getNumReplacementTypes() const {
83+
return genericSig->getGenericParams().size();
84+
}
85+
86+
size_t numTrailingObjects(OverloadToken<Type>) const {
87+
return getNumReplacementTypes();
88+
}
89+
90+
size_t numTrailingObjects(OverloadToken<ProtocolConformanceRef>) const {
91+
return numConformanceRequirements;
92+
}
93+
94+
public:
95+
/// Form storage for the given generic signature and its replacement
96+
/// types and conformances.
97+
static Storage *get(GenericSignature *genericSig,
98+
ArrayRef<Type> replacementTypes,
99+
ArrayRef<ProtocolConformanceRef> conformances);
100+
101+
/// Retrieve the generic signature that describes the shape of this
102+
/// storage.
103+
GenericSignature *getGenericSignature() const { return genericSig; }
104+
105+
/// Retrieve the array of replacement types, which line up with the
106+
/// generic parameters.
107+
///
108+
/// Note that the types may be null, for cases where the generic parameter
109+
/// is concrete but hasn't been queried yet.
110+
ArrayRef<Type> getReplacementTypes() const {
111+
return llvm::makeArrayRef(getTrailingObjects<Type>(),
112+
getNumReplacementTypes());
113+
}
114+
115+
MutableArrayRef<Type> getReplacementTypes() {
116+
return MutableArrayRef<Type>(getTrailingObjects<Type>(),
117+
getNumReplacementTypes());
118+
}
119+
120+
/// Retrieve the array of protocol conformances, which line up with the
121+
/// requirements of the generic signature.
122+
ArrayRef<ProtocolConformanceRef> getConformances() const {
123+
return llvm::makeArrayRef(getTrailingObjects<ProtocolConformanceRef>(),
124+
numConformanceRequirements);
125+
}
126+
MutableArrayRef<ProtocolConformanceRef> getConformances() {
127+
return MutableArrayRef<ProtocolConformanceRef>(
128+
getTrailingObjects<ProtocolConformanceRef>(),
129+
numConformanceRequirements);
130+
}
131+
132+
/// Profile the substitution map storage, for use with LLVM's FoldingSet.
133+
void Profile(llvm::FoldingSetNodeID &id) const {
134+
Profile(id, getGenericSignature(), getReplacementTypes(),
135+
getConformances());
136+
}
137+
138+
/// Profile the substitution map storage, for use with LLVM's FoldingSet.
139+
static void Profile(llvm::FoldingSetNodeID &id,
140+
GenericSignature *genericSig,
141+
ArrayRef<Type> replacementTypes,
142+
ArrayRef<ProtocolConformanceRef> conformances);
143+
};
64144

65-
// FIXME: Switch to a more efficient representation that corresponds to
66-
// the conformance requirements in the GenericSignature.
67-
llvm::DenseMap<CanType, SmallVector<ProtocolConformanceRef, 1>>
68-
conformanceMap;
145+
private:
146+
/// The storage needed to describe the set of substitutions.
147+
///
148+
/// When null, this substitution map is empty, having neither a generic
149+
/// signature nor any replacement types/conformances.
150+
Storage *storage = nullptr;
69151

70152
/// Retrieve the array of replacement types, which line up with the
71153
/// generic parameters.
72154
///
73155
/// Note that the types may be null, for cases where the generic parameter
74156
/// is concrete but hasn't been queried yet.
75-
ArrayRef<Type> getReplacementTypes() const;
76-
77-
MutableArrayRef<Type> getReplacementTypes();
157+
ArrayRef<Type> getReplacementTypes() const {
158+
return storage ? storage->getReplacementTypes() : ArrayRef<Type>();
159+
}
160+
161+
MutableArrayRef<Type> getReplacementTypes() {
162+
return storage ? storage->getReplacementTypes() : MutableArrayRef<Type>();
163+
}
164+
165+
/// Retrieve the array of protocol conformances, which line up with the
166+
/// requirements of the generic signature.
167+
ArrayRef<ProtocolConformanceRef> getConformances() const {
168+
return storage ? storage->getConformances()
169+
: ArrayRef<ProtocolConformanceRef>();
170+
}
171+
MutableArrayRef<ProtocolConformanceRef> getConformances() {
172+
return storage ? storage->getConformances()
173+
: MutableArrayRef<ProtocolConformanceRef>();
174+
}
175+
176+
/// Form a substitution map for the given generic signature with the
177+
/// specified replacement types and conformances.
178+
SubstitutionMap(GenericSignature *genericSig,
179+
ArrayRef<Type> replacementTypes,
180+
ArrayRef<ProtocolConformanceRef> conformances)
181+
: storage(Storage::get(genericSig, replacementTypes, conformances)) { }
78182

79183
public:
80-
SubstitutionMap()
81-
: SubstitutionMap(static_cast<GenericSignature *>(nullptr)) { }
82-
83-
SubstitutionMap(GenericSignature *genericSig);
84-
85-
SubstitutionMap(GenericEnvironment *genericEnv);
86-
87-
SubstitutionMap(SubstitutionMap &&other) = default;
88-
SubstitutionMap &operator=(SubstitutionMap &&other) = default;
184+
/// Build an empty substitution map.
185+
SubstitutionMap() { }
89186

90-
SubstitutionMap(const SubstitutionMap &other);
187+
/// Build an interface type substitution map for the given generic
188+
/// signature and a vector of Substitutions that correspond to the
189+
/// requirements of this generic signature.
190+
static SubstitutionMap get(GenericSignature *genericSig,
191+
SubstitutionList substitutions);
91192

92-
SubstitutionMap &operator=(const SubstitutionMap &other);
93-
94-
~SubstitutionMap();
193+
/// Build an interface type substitution map for the given generic signature
194+
/// from a type substitution function and conformance lookup function.
195+
static SubstitutionMap get(GenericSignature *genericSig,
196+
TypeSubstitutionFn subs,
197+
LookupConformanceFn lookupConformance);
95198

96199
/// Retrieve the generic signature describing the environment in which
97200
/// substitutions occur.
98-
GenericSignature *getGenericSignature() const { return genericSig; }
201+
GenericSignature *getGenericSignature() const {
202+
return storage ? storage->getGenericSignature() : nullptr;
203+
}
99204

205+
/// Look up a conformance for the given type to the given protocol.
100206
Optional<ProtocolConformanceRef>
101207
lookupConformance(CanType type, ProtocolDecl *proto) const;
102208

@@ -191,13 +297,6 @@ class SubstitutionMap {
191297
/// stored inside the map. In most cases, you should call Type::subst()
192298
/// instead, since that will resolve member types also.
193299
Type lookupSubstitution(CanSubstitutableType type) const;
194-
195-
// You should not need to call these directly to build SubstitutionMaps;
196-
// instead, use GenericSignature::getSubstitutionMap() or
197-
// GenericEnvironment::getSubstitutionMap().
198-
199-
void addSubstitution(CanGenericTypeParamType type, Type replacement);
200-
void addConformance(CanType type, ProtocolConformanceRef conformance);
201300
};
202301

203302
} // end namespace swift

lib/AST/ASTContext.cpp

Lines changed: 64 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,9 @@ FOR_KNOWN_FOUNDATION_TYPES(CACHE_FOUNDATION_DECL)
309309
/// The set of inherited protocol conformances.
310310
llvm::FoldingSet<InheritedProtocolConformance> InheritedConformances;
311311

312+
/// The set of substitution maps (uniqued by their storage).
313+
llvm::FoldingSet<SubstitutionMap::Storage> SubstitutionMaps;
314+
312315
~Arena() {
313316
for (auto &conformance : SpecializedConformances)
314317
conformance.~SpecializedProtocolConformance();
@@ -2908,11 +2911,9 @@ NameAliasType::NameAliasType(TypeAliasDecl *typealias, Type parent,
29082911
}
29092912
}
29102913

2911-
NameAliasType *NameAliasType::get(
2912-
TypeAliasDecl *typealias,
2913-
Type parent,
2914-
const SubstitutionMap &substitutions,
2915-
Type underlying) {
2914+
NameAliasType *NameAliasType::get(TypeAliasDecl *typealias, Type parent,
2915+
const SubstitutionMap &substitutions,
2916+
Type underlying) {
29162917
// Compute the recursive properties.
29172918
//
29182919
auto properties = underlying->getRecursiveProperties();
@@ -4307,6 +4308,64 @@ CapturingTypeCheckerDebugConsumer::~CapturingTypeCheckerDebugConsumer() {
43074308
delete Log;
43084309
}
43094310

4311+
void SubstitutionMap::Storage::Profile(
4312+
llvm::FoldingSetNodeID &id,
4313+
GenericSignature *genericSig,
4314+
ArrayRef<Type> replacementTypes,
4315+
ArrayRef<ProtocolConformanceRef> conformances) {
4316+
id.AddPointer(genericSig);
4317+
id.AddInteger(replacementTypes.size());
4318+
for (auto type : replacementTypes)
4319+
id.AddPointer(type.getPointer());
4320+
id.AddInteger(conformances.size());
4321+
for (auto conformance : conformances)
4322+
id.AddPointer(conformance.getOpaqueValue());
4323+
}
4324+
4325+
SubstitutionMap::Storage *SubstitutionMap::Storage::get(
4326+
GenericSignature *genericSig,
4327+
ArrayRef<Type> replacementTypes,
4328+
ArrayRef<ProtocolConformanceRef> conformances) {
4329+
// If there is no generic signature, we need no storage.
4330+
if (!genericSig) {
4331+
assert(replacementTypes.empty());
4332+
assert(conformances.empty());
4333+
return nullptr;
4334+
}
4335+
4336+
// Figure out which arena this should go in.
4337+
RecursiveTypeProperties properties;
4338+
for (auto type : replacementTypes) {
4339+
if (type)
4340+
properties |= type->getRecursiveProperties();
4341+
}
4342+
4343+
// Profile the substitution map.
4344+
llvm::FoldingSetNodeID id;
4345+
SubstitutionMap::Storage::Profile(id, genericSig, replacementTypes,
4346+
conformances);
4347+
4348+
auto arena = getArena(properties);
4349+
4350+
// Did we already record this substitution map?
4351+
auto &ctx = genericSig->getASTContext();
4352+
void *insertPos;
4353+
auto &substitutionMaps = ctx.Impl.getArena(arena).SubstitutionMaps;
4354+
if (auto result = substitutionMaps.FindNodeOrInsertPos(id, insertPos))
4355+
return result;
4356+
4357+
// Allocate the appropriate amount of storage for the signature and its
4358+
// replacement types and conformances.
4359+
auto size = Storage::totalSizeToAlloc<Type, ProtocolConformanceRef>(
4360+
replacementTypes.size(),
4361+
conformances.size());
4362+
auto mem = ctx.Allocate(size, alignof(Storage), arena);
4363+
4364+
auto result = new (mem) Storage(genericSig, replacementTypes, conformances);
4365+
substitutionMaps.InsertNode(result, insertPos);
4366+
return result;
4367+
}
4368+
43104369
void GenericSignature::Profile(llvm::FoldingSetNodeID &ID,
43114370
TypeArrayView<GenericTypeParamType> genericParams,
43124371
ArrayRef<Requirement> requirements) {

0 commit comments

Comments
 (0)