Skip to content

Commit 6bdd24d

Browse files
authored
Merge pull request #16268 from DougGregor/substitution-map-ast-adoption
[AST] Adopt SubstitutionMap as the storage mechanism for substitutions
2 parents 815365e + df97e44 commit 6bdd24d

File tree

12 files changed

+323
-118
lines changed

12 files changed

+323
-118
lines changed

include/swift/AST/GenericSignature.h

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
#include "swift/AST/PrintOptions.h"
2121
#include "swift/AST/Requirement.h"
2222
#include "swift/AST/SubstitutionList.h"
23-
#include "swift/AST/Types.h"
23+
#include "swift/AST/Type.h"
2424
#include "llvm/ADT/ArrayRef.h"
2525
#include "llvm/ADT/FoldingSet.h"
2626
#include "llvm/ADT/SmallVector.h"
@@ -361,14 +361,6 @@ CanGenericSignature::CanGenericSignature(GenericSignature *Signature)
361361
{
362362
assert(!Signature || Signature->isCanonical());
363363
}
364-
365-
inline ArrayRef<CanTypeWrapper<GenericTypeParamType>>
366-
CanGenericSignature::getGenericParams() const{
367-
auto params = Signature->getGenericParams().getOriginalArray();
368-
auto base = static_cast<const CanTypeWrapper<GenericTypeParamType>*>(
369-
params.data());
370-
return {base, params.size()};
371-
}
372364

373365
} // end namespace swift
374366

include/swift/AST/SubstitutionMap.h

Lines changed: 89 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "swift/AST/SubstitutionList.h"
2323
#include "swift/AST/Type.h"
2424
#include "llvm/ADT/ArrayRef.h"
25+
#include "llvm/ADT/DenseMapInfo.h"
2526
#include "llvm/ADT/FoldingSet.h"
2627
#include "llvm/ADT/Optional.h"
2728
#include "llvm/Support/TrailingObjects.h"
@@ -48,13 +49,18 @@ enum class CombineSubstitutionMaps {
4849
/// abstract types to replacement types, together with associated conformances
4950
/// to use for deriving nested types and conformances.
5051
///
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.
52+
/// Substitution maps are primarily used when performing substitutions into
53+
/// any entity that can reference type parameters, e.g., types (via
54+
/// Type::subst()) and conformances (via ProtocolConformanceRef::subst()).
5455
///
5556
/// SubstitutionMaps are constructed by calling the getSubstitutionMap() method
5657
/// on a GenericSignature or (equivalently) by calling one of the static
57-
/// \c SubstitutionMap::get() methods.
58+
/// \c SubstitutionMap::get() methods. However, most substitution maps are
59+
/// computed using higher-level entry points such as
60+
/// TypeBase::getMemberSubstitutionMap().
61+
///
62+
/// Substitution maps are ASTContext-allocated and are uniqued on construction,
63+
/// so they can be used as fields in AST nodes.
5864
class SubstitutionMap {
5965
public:
6066
/// Stored data for a substitution map, which uses tail allocation for the
@@ -149,25 +155,10 @@ class SubstitutionMap {
149155
/// signature nor any replacement types/conformances.
150156
Storage *storage = nullptr;
151157

152-
/// Retrieve the array of replacement types, which line up with the
153-
/// generic parameters.
154-
///
155-
/// Note that the types may be null, for cases where the generic parameter
156-
/// is concrete but hasn't been queried yet.
157-
ArrayRef<Type> getReplacementTypes() const {
158-
return storage ? storage->getReplacementTypes() : ArrayRef<Type>();
159-
}
160-
161158
MutableArrayRef<Type> getReplacementTypes() {
162159
return storage ? storage->getReplacementTypes() : MutableArrayRef<Type>();
163160
}
164161

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-
}
171162
MutableArrayRef<ProtocolConformanceRef> getConformances() {
172163
return storage ? storage->getConformances()
173164
: MutableArrayRef<ProtocolConformanceRef>();
@@ -180,10 +171,21 @@ class SubstitutionMap {
180171
ArrayRef<ProtocolConformanceRef> conformances)
181172
: storage(Storage::get(genericSig, replacementTypes, conformances)) { }
182173

174+
explicit SubstitutionMap(Storage *storage) : storage(storage) { }
175+
183176
public:
184177
/// Build an empty substitution map.
185178
SubstitutionMap() { }
186179

180+
/// Build an interface type substitution map for the given generic
181+
/// signature and a vector of Substitutions that correspond to the
182+
/// requirements of this generic signature.
183+
static SubstitutionMap get(GenericSignature *genericSig,
184+
ArrayRef<Type> replacementTypes,
185+
ArrayRef<ProtocolConformanceRef> conformances) {
186+
return SubstitutionMap(genericSig, replacementTypes, conformances);
187+
}
188+
187189
/// Build an interface type substitution map for the given generic
188190
/// signature and a vector of Substitutions that correspond to the
189191
/// requirements of this generic signature.
@@ -202,13 +204,32 @@ class SubstitutionMap {
202204
return storage ? storage->getGenericSignature() : nullptr;
203205
}
204206

207+
/// Retrieve the array of protocol conformances, which line up with the
208+
/// requirements of the generic signature.
209+
ArrayRef<ProtocolConformanceRef> getConformances() const {
210+
return storage ? storage->getConformances()
211+
: ArrayRef<ProtocolConformanceRef>();
212+
}
213+
205214
/// Look up a conformance for the given type to the given protocol.
206215
Optional<ProtocolConformanceRef>
207216
lookupConformance(CanType type, ProtocolDecl *proto) const;
208217

209218
/// Whether the substitution map is empty.
210219
bool empty() const { return getGenericSignature() == nullptr; }
211220

221+
/// Whether the substitution map is non-empty.
222+
explicit operator bool() const { return !empty(); }
223+
224+
/// Retrieve the array of replacement types, which line up with the
225+
/// generic parameters.
226+
///
227+
/// Note that the types may be null, for cases where the generic parameter
228+
/// is concrete but hasn't been queried yet.
229+
ArrayRef<Type> getReplacementTypes() const {
230+
return storage ? storage->getReplacementTypes() : ArrayRef<Type>();
231+
}
232+
212233
/// Query whether any replacement types in the map contain archetypes.
213234
bool hasArchetypes() const;
214235

@@ -287,6 +308,22 @@ class SubstitutionMap {
287308
/// Profile the substitution map, for use with LLVM's FoldingSet.
288309
void profile(llvm::FoldingSetNodeID &id) const;
289310

311+
const void *getOpaqueValue() const { return storage; }
312+
313+
static SubstitutionMap getFromOpaqueValue(const void *ptr) {
314+
return SubstitutionMap(const_cast<Storage *>((const Storage *)ptr));
315+
}
316+
317+
static SubstitutionMap getEmptyKey() {
318+
return SubstitutionMap(
319+
(Storage *)llvm::DenseMapInfo<void*>::getEmptyKey());
320+
}
321+
322+
static SubstitutionMap getTombstoneKey() {
323+
return SubstitutionMap(
324+
(Storage *)llvm::DenseMapInfo<void*>::getTombstoneKey());
325+
}
326+
290327
private:
291328
friend class GenericSignature;
292329
friend class GenericEnvironment;
@@ -301,4 +338,37 @@ class SubstitutionMap {
301338

302339
} // end namespace swift
303340

341+
namespace llvm {
342+
template <>
343+
struct PointerLikeTypeTraits<swift::SubstitutionMap> {
344+
static void *getAsVoidPointer(swift::SubstitutionMap map) {
345+
return const_cast<void *>(map.getOpaqueValue());
346+
}
347+
static swift::SubstitutionMap getFromVoidPointer(const void *ptr) {
348+
return swift::SubstitutionMap::getFromOpaqueValue(ptr);
349+
}
350+
351+
/// Note: Assuming storage is at leaste 4-byte aligned.
352+
enum { NumLowBitsAvailable = 2 };
353+
};
354+
355+
// Substitution maps hash just like pointers.
356+
template<> struct DenseMapInfo<swift::SubstitutionMap> {
357+
static swift::SubstitutionMap getEmptyKey() {
358+
return swift::SubstitutionMap::getEmptyKey();
359+
}
360+
static swift::SubstitutionMap getTombstoneKey() {
361+
return swift::SubstitutionMap::getTombstoneKey();
362+
}
363+
static unsigned getHashValue(swift::SubstitutionMap map) {
364+
return DenseMapInfo<void*>::getHashValue(map.getOpaqueValue());
365+
}
366+
static bool isEqual(swift::SubstitutionMap lhs,
367+
swift::SubstitutionMap rhs) {
368+
return lhs.getOpaqueValue() == rhs.getOpaqueValue();
369+
}
370+
};
371+
372+
}
373+
304374
#endif

include/swift/AST/Types.h

Lines changed: 25 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "swift/AST/Requirement.h"
2626
#include "swift/AST/SILLayout.h"
2727
#include "swift/AST/SubstitutionList.h"
28+
#include "swift/AST/SubstitutionMap.h"
2829
#include "swift/AST/Type.h"
2930
#include "swift/AST/TypeAlignments.h"
3031
#include "swift/Basic/ArrayRefView.h"
@@ -373,14 +374,14 @@ class alignas(1 << TypeAlignInBits) TypeBase {
373374
GenericArgCount : 32
374375
);
375376

376-
SWIFT_INLINE_BITFIELD_FULL(NameAliasType, SugarType, 1+16,
377+
SWIFT_INLINE_BITFIELD_FULL(NameAliasType, SugarType, 1+1,
377378
: NumPadBits,
378379

379380
/// Whether we have a parent type.
380381
HasParent : 1,
381382

382-
/// The number of substitutions.
383-
NumSubstitutions : 16
383+
/// Whether we have a substitution map.
384+
HasSubstitutionMap : 1
384385
);
385386

386387
} Bits;
@@ -1592,39 +1593,28 @@ class SugarType : public TypeBase {
15921593
/// set of substitutions to apply to make the type concrete.
15931594
class NameAliasType final
15941595
: public SugarType, public llvm::FoldingSetNode,
1595-
llvm::TrailingObjects<NameAliasType, Type, GenericSignature *,
1596-
Substitution>
1596+
llvm::TrailingObjects<NameAliasType, Type, SubstitutionMap>
15971597
{
15981598
TypeAliasDecl *typealias;
15991599

16001600
friend class ASTContext;
16011601
friend TrailingObjects;
16021602

16031603
NameAliasType(TypeAliasDecl *typealias, Type parent,
1604-
const SubstitutionMap &substitutions, Type underlying,
1605-
RecursiveTypeProperties properties);
1606-
1607-
unsigned getNumSubstitutions() const {
1608-
return Bits.NameAliasType.NumSubstitutions;
1609-
}
1604+
const SubstitutionMap &substitutions, Type underlying,
1605+
RecursiveTypeProperties properties);
16101606

16111607
size_t numTrailingObjects(OverloadToken<Type>) const {
16121608
return Bits.NameAliasType.HasParent ? 1 : 0;
16131609
}
16141610

1615-
size_t numTrailingObjects(OverloadToken<GenericSignature *>) const {
1616-
return getNumSubstitutions() > 0 ? 1 : 0;
1617-
}
1618-
1619-
size_t numTrailingObjects(OverloadToken<Substitution>) const {
1620-
return getNumSubstitutions();
1611+
size_t numTrailingObjects(OverloadToken<SubstitutionMap>) const {
1612+
return Bits.NameAliasType.HasSubstitutionMap ? 1 : 0;
16211613
}
16221614

16231615
/// Retrieve the generic signature used for substitutions.
16241616
GenericSignature *getGenericSignature() const {
1625-
return getNumSubstitutions() > 0
1626-
? *getTrailingObjects<GenericSignature *>()
1627-
: nullptr;
1617+
return getSubstitutionMap().getGenericSignature();
16281618
}
16291619

16301620
public:
@@ -1642,18 +1632,17 @@ class NameAliasType final
16421632
/// written before ".", if provided.
16431633
Type getParent() const {
16441634
return Bits.NameAliasType.HasParent ? *getTrailingObjects<Type>()
1645-
: Type();
1646-
}
1647-
1648-
/// Retrieve the set of substitutions to be applied to the declaration to
1649-
/// produce the underlying type.
1650-
SubstitutionList getSubstitutionList() const {
1651-
return {getTrailingObjects<Substitution>(), getNumSubstitutions()};
1635+
: Type();
16521636
}
16531637

16541638
/// Retrieve the substitution map applied to the declaration's underlying
16551639
/// to produce the described type.
1656-
SubstitutionMap getSubstitutionMap() const;
1640+
SubstitutionMap getSubstitutionMap() const {
1641+
if (!Bits.NameAliasType.HasSubstitutionMap)
1642+
return SubstitutionMap();
1643+
1644+
return *getTrailingObjects<SubstitutionMap>();
1645+
}
16571646

16581647
/// Get the innermost generic arguments, which correspond to the generic
16591648
/// arguments that are directly applied to the typealias declaration in
@@ -5412,6 +5401,14 @@ inline bool TypeBase::hasSimpleTypeRepr() const {
54125401
}
54135402
}
54145403

5404+
inline ArrayRef<CanTypeWrapper<GenericTypeParamType>>
5405+
CanGenericSignature::getGenericParams() const{
5406+
auto params = Signature->getGenericParams().getOriginalArray();
5407+
auto base = static_cast<const CanTypeWrapper<GenericTypeParamType>*>(
5408+
params.data());
5409+
return {base, params.size()};
5410+
}
5411+
54155412
} // end namespace swift
54165413

54175414
namespace llvm {
@@ -5438,7 +5435,6 @@ struct DenseMapInfo<swift::BuiltinIntegerWidth> {
54385435
}
54395436
};
54405437

5441-
54425438
}
54435439

54445440
#endif

include/swift/Serialization/DeclTypeRecordNodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ TRAILING_INFO(GENERIC_REQUIREMENT)
166166
TRAILING_INFO(LAYOUT_REQUIREMENT)
167167
OTHER(GENERIC_SIGNATURE, 244)
168168
OTHER(SIL_GENERIC_ENVIRONMENT, 245)
169+
OTHER(SUBSTITUTION_MAP, 246)
169170

170171
OTHER(LOCAL_DISCRIMINATOR, 248)
171172
OTHER(PRIVATE_DISCRIMINATOR, 249)

include/swift/Serialization/ModuleFile.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,9 @@ class ModuleFile
308308
/// Generic environments referenced by this module.
309309
std::vector<Serialized<GenericEnvironment *>> GenericEnvironments;
310310

311+
/// Substitution maps referenced by this module.
312+
std::vector<Serialized<SubstitutionMap>> SubstitutionMaps;
313+
311314
/// Represents an identifier that may or may not have been deserialized yet.
312315
///
313316
/// If \c Offset is non-zero, the identifier has not been loaded yet.
@@ -836,6 +839,10 @@ class ModuleFile
836839
GenericEnvironment *getGenericEnvironment(
837840
serialization::GenericEnvironmentID ID);
838841

842+
/// Returns the substitution map for the given ID, deserializing it if
843+
/// needed.
844+
SubstitutionMap getSubstitutionMap(serialization::SubstitutionMapID id);
845+
839846
/// Reads a substitution record from \c DeclTypeCursor.
840847
///
841848
/// If the record at the cursor is not a substitution, returns None.

0 commit comments

Comments
 (0)