Skip to content

[AST] Adopt SubstitutionMap as the storage mechanism for substitutions #16268

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 1 addition & 9 deletions include/swift/AST/GenericSignature.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
#include "swift/AST/PrintOptions.h"
#include "swift/AST/Requirement.h"
#include "swift/AST/SubstitutionList.h"
#include "swift/AST/Types.h"
#include "swift/AST/Type.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/SmallVector.h"
Expand Down Expand Up @@ -361,14 +361,6 @@ CanGenericSignature::CanGenericSignature(GenericSignature *Signature)
{
assert(!Signature || Signature->isCanonical());
}

inline ArrayRef<CanTypeWrapper<GenericTypeParamType>>
CanGenericSignature::getGenericParams() const{
auto params = Signature->getGenericParams().getOriginalArray();
auto base = static_cast<const CanTypeWrapper<GenericTypeParamType>*>(
params.data());
return {base, params.size()};
}

} // end namespace swift

Expand Down
108 changes: 89 additions & 19 deletions include/swift/AST/SubstitutionMap.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "swift/AST/SubstitutionList.h"
#include "swift/AST/Type.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMapInfo.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/Optional.h"
#include "llvm/Support/TrailingObjects.h"
Expand All @@ -48,13 +49,18 @@ enum class CombineSubstitutionMaps {
/// abstract types to replacement types, together with associated conformances
/// to use for deriving nested types and conformances.
///
/// Depending on how the SubstitutionMap is constructed, the abstract types are
/// either archetypes or interface types. Care must be exercised to only look
/// up one or the other.
/// Substitution maps are primarily used when performing substitutions into
/// any entity that can reference type parameters, e.g., types (via
/// Type::subst()) and conformances (via ProtocolConformanceRef::subst()).
///
/// SubstitutionMaps are constructed by calling the getSubstitutionMap() method
/// on a GenericSignature or (equivalently) by calling one of the static
/// \c SubstitutionMap::get() methods.
/// \c SubstitutionMap::get() methods. However, most substitution maps are
/// computed using higher-level entry points such as
/// TypeBase::getMemberSubstitutionMap().
///
/// Substitution maps are ASTContext-allocated and are uniqued on construction,
/// so they can be used as fields in AST nodes.
class SubstitutionMap {
public:
/// Stored data for a substitution map, which uses tail allocation for the
Expand Down Expand Up @@ -149,25 +155,10 @@ class SubstitutionMap {
/// signature nor any replacement types/conformances.
Storage *storage = nullptr;

/// Retrieve the array of replacement types, which line up with the
/// generic parameters.
///
/// Note that the types may be null, for cases where the generic parameter
/// is concrete but hasn't been queried yet.
ArrayRef<Type> getReplacementTypes() const {
return storage ? storage->getReplacementTypes() : ArrayRef<Type>();
}

MutableArrayRef<Type> getReplacementTypes() {
return storage ? storage->getReplacementTypes() : MutableArrayRef<Type>();
}

/// Retrieve the array of protocol conformances, which line up with the
/// requirements of the generic signature.
ArrayRef<ProtocolConformanceRef> getConformances() const {
return storage ? storage->getConformances()
: ArrayRef<ProtocolConformanceRef>();
}
MutableArrayRef<ProtocolConformanceRef> getConformances() {
return storage ? storage->getConformances()
: MutableArrayRef<ProtocolConformanceRef>();
Expand All @@ -180,10 +171,21 @@ class SubstitutionMap {
ArrayRef<ProtocolConformanceRef> conformances)
: storage(Storage::get(genericSig, replacementTypes, conformances)) { }

explicit SubstitutionMap(Storage *storage) : storage(storage) { }

public:
/// Build an empty substitution map.
SubstitutionMap() { }

/// Build an interface type substitution map for the given generic
/// signature and a vector of Substitutions that correspond to the
/// requirements of this generic signature.
static SubstitutionMap get(GenericSignature *genericSig,
ArrayRef<Type> replacementTypes,
ArrayRef<ProtocolConformanceRef> conformances) {
return SubstitutionMap(genericSig, replacementTypes, conformances);
}

/// Build an interface type substitution map for the given generic
/// signature and a vector of Substitutions that correspond to the
/// requirements of this generic signature.
Expand All @@ -202,13 +204,32 @@ class SubstitutionMap {
return storage ? storage->getGenericSignature() : nullptr;
}

/// Retrieve the array of protocol conformances, which line up with the
/// requirements of the generic signature.
ArrayRef<ProtocolConformanceRef> getConformances() const {
return storage ? storage->getConformances()
: ArrayRef<ProtocolConformanceRef>();
}

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

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

/// Whether the substitution map is non-empty.
explicit operator bool() const { return !empty(); }

/// Retrieve the array of replacement types, which line up with the
/// generic parameters.
///
/// Note that the types may be null, for cases where the generic parameter
/// is concrete but hasn't been queried yet.
ArrayRef<Type> getReplacementTypes() const {
return storage ? storage->getReplacementTypes() : ArrayRef<Type>();
}

/// Query whether any replacement types in the map contain archetypes.
bool hasArchetypes() const;

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

const void *getOpaqueValue() const { return storage; }

static SubstitutionMap getFromOpaqueValue(const void *ptr) {
return SubstitutionMap(const_cast<Storage *>((const Storage *)ptr));
}

static SubstitutionMap getEmptyKey() {
return SubstitutionMap(
(Storage *)llvm::DenseMapInfo<void*>::getEmptyKey());
}

static SubstitutionMap getTombstoneKey() {
return SubstitutionMap(
(Storage *)llvm::DenseMapInfo<void*>::getTombstoneKey());
}

private:
friend class GenericSignature;
friend class GenericEnvironment;
Expand All @@ -301,4 +338,37 @@ class SubstitutionMap {

} // end namespace swift

namespace llvm {
template <>
struct PointerLikeTypeTraits<swift::SubstitutionMap> {
static void *getAsVoidPointer(swift::SubstitutionMap map) {
return const_cast<void *>(map.getOpaqueValue());
}
static swift::SubstitutionMap getFromVoidPointer(const void *ptr) {
return swift::SubstitutionMap::getFromOpaqueValue(ptr);
}

/// Note: Assuming storage is at leaste 4-byte aligned.
enum { NumLowBitsAvailable = 2 };
};

// Substitution maps hash just like pointers.
template<> struct DenseMapInfo<swift::SubstitutionMap> {
static swift::SubstitutionMap getEmptyKey() {
return swift::SubstitutionMap::getEmptyKey();
}
static swift::SubstitutionMap getTombstoneKey() {
return swift::SubstitutionMap::getTombstoneKey();
}
static unsigned getHashValue(swift::SubstitutionMap map) {
return DenseMapInfo<void*>::getHashValue(map.getOpaqueValue());
}
static bool isEqual(swift::SubstitutionMap lhs,
swift::SubstitutionMap rhs) {
return lhs.getOpaqueValue() == rhs.getOpaqueValue();
}
};

}

#endif
54 changes: 25 additions & 29 deletions include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "swift/AST/Requirement.h"
#include "swift/AST/SILLayout.h"
#include "swift/AST/SubstitutionList.h"
#include "swift/AST/SubstitutionMap.h"
#include "swift/AST/Type.h"
#include "swift/AST/TypeAlignments.h"
#include "swift/Basic/ArrayRefView.h"
Expand Down Expand Up @@ -373,14 +374,14 @@ class alignas(1 << TypeAlignInBits) TypeBase {
GenericArgCount : 32
);

SWIFT_INLINE_BITFIELD_FULL(NameAliasType, SugarType, 1+16,
SWIFT_INLINE_BITFIELD_FULL(NameAliasType, SugarType, 1+1,
: NumPadBits,

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

/// The number of substitutions.
NumSubstitutions : 16
/// Whether we have a substitution map.
HasSubstitutionMap : 1
);

} Bits;
Expand Down Expand Up @@ -1592,39 +1593,28 @@ class SugarType : public TypeBase {
/// set of substitutions to apply to make the type concrete.
class NameAliasType final
: public SugarType, public llvm::FoldingSetNode,
llvm::TrailingObjects<NameAliasType, Type, GenericSignature *,
Substitution>
llvm::TrailingObjects<NameAliasType, Type, SubstitutionMap>
{
TypeAliasDecl *typealias;

friend class ASTContext;
friend TrailingObjects;

NameAliasType(TypeAliasDecl *typealias, Type parent,
const SubstitutionMap &substitutions, Type underlying,
RecursiveTypeProperties properties);

unsigned getNumSubstitutions() const {
return Bits.NameAliasType.NumSubstitutions;
}
const SubstitutionMap &substitutions, Type underlying,
RecursiveTypeProperties properties);

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

size_t numTrailingObjects(OverloadToken<GenericSignature *>) const {
return getNumSubstitutions() > 0 ? 1 : 0;
}

size_t numTrailingObjects(OverloadToken<Substitution>) const {
return getNumSubstitutions();
size_t numTrailingObjects(OverloadToken<SubstitutionMap>) const {
return Bits.NameAliasType.HasSubstitutionMap ? 1 : 0;
}

/// Retrieve the generic signature used for substitutions.
GenericSignature *getGenericSignature() const {
return getNumSubstitutions() > 0
? *getTrailingObjects<GenericSignature *>()
: nullptr;
return getSubstitutionMap().getGenericSignature();
}

public:
Expand All @@ -1642,18 +1632,17 @@ class NameAliasType final
/// written before ".", if provided.
Type getParent() const {
return Bits.NameAliasType.HasParent ? *getTrailingObjects<Type>()
: Type();
}

/// Retrieve the set of substitutions to be applied to the declaration to
/// produce the underlying type.
SubstitutionList getSubstitutionList() const {
return {getTrailingObjects<Substitution>(), getNumSubstitutions()};
: Type();
}

/// Retrieve the substitution map applied to the declaration's underlying
/// to produce the described type.
SubstitutionMap getSubstitutionMap() const;
SubstitutionMap getSubstitutionMap() const {
if (!Bits.NameAliasType.HasSubstitutionMap)
return SubstitutionMap();

return *getTrailingObjects<SubstitutionMap>();
}

/// Get the innermost generic arguments, which correspond to the generic
/// arguments that are directly applied to the typealias declaration in
Expand Down Expand Up @@ -5395,6 +5384,14 @@ inline bool TypeBase::hasSimpleTypeRepr() const {
}
}

inline ArrayRef<CanTypeWrapper<GenericTypeParamType>>
CanGenericSignature::getGenericParams() const{
auto params = Signature->getGenericParams().getOriginalArray();
auto base = static_cast<const CanTypeWrapper<GenericTypeParamType>*>(
params.data());
return {base, params.size()};
}

} // end namespace swift

namespace llvm {
Expand All @@ -5421,7 +5418,6 @@ struct DenseMapInfo<swift::BuiltinIntegerWidth> {
}
};


}

#endif
1 change: 1 addition & 0 deletions include/swift/Serialization/DeclTypeRecordNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ TRAILING_INFO(GENERIC_REQUIREMENT)
TRAILING_INFO(LAYOUT_REQUIREMENT)
OTHER(GENERIC_SIGNATURE, 244)
OTHER(SIL_GENERIC_ENVIRONMENT, 245)
OTHER(SUBSTITUTION_MAP, 246)

OTHER(LOCAL_DISCRIMINATOR, 248)
OTHER(PRIVATE_DISCRIMINATOR, 249)
Expand Down
7 changes: 7 additions & 0 deletions include/swift/Serialization/ModuleFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,9 @@ class ModuleFile
/// Generic environments referenced by this module.
std::vector<Serialized<GenericEnvironment *>> GenericEnvironments;

/// Substitution maps referenced by this module.
std::vector<Serialized<SubstitutionMap>> SubstitutionMaps;

/// Represents an identifier that may or may not have been deserialized yet.
///
/// If \c Offset is non-zero, the identifier has not been loaded yet.
Expand Down Expand Up @@ -844,6 +847,10 @@ class ModuleFile
GenericEnvironment *getGenericEnvironment(
serialization::GenericEnvironmentID ID);

/// Returns the substitution map for the given ID, deserializing it if
/// needed.
SubstitutionMap getSubstitutionMap(serialization::SubstitutionMapID id);

/// Reads a substitution record from \c DeclTypeCursor.
///
/// If the record at the cursor is not a substitution, returns None.
Expand Down
Loading