blob: cc03f16547afc833b079e232407e0aa828665c87 [file] [log] [blame]
//===--- TypeRef.h - Swift Type References for Reflection -------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// Implements the structures of type references for property and enum
// case reflection.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_REFLECTION_TYPEREF_H
#define SWIFT_REFLECTION_TYPEREF_H
#include "llvm/ADT/DenseMap.h"
#include "llvm/Support/Casting.h"
#include "swift/ABI/MetadataValues.h"
#include "swift/Remote/MetadataReader.h"
#include "swift/Runtime/Unreachable.h"
#include <iostream>
namespace swift {
namespace reflection {
using llvm::cast;
using llvm::dyn_cast;
enum class TypeRefKind {
#define TYPEREF(Id, Parent) Id,
#include "swift/Reflection/TypeRefs.def"
#undef TYPEREF
};
// MSVC reports an error if we use "template"
// Clang reports an error if we don't use "template"
#if defined(__clang__) || defined(__GNUC__)
# define DEPENDENT_TEMPLATE template
#else
# define DEPENDENT_TEMPLATE
#endif
#define FIND_OR_CREATE_TYPEREF(Allocator, TypeRefTy, ...) \
auto ID = Profile(__VA_ARGS__); \
const auto Entry = Allocator.TypeRefTy##s.find(ID); \
if (Entry != Allocator.TypeRefTy##s.end()) \
return Entry->second; \
const auto TR = \
Allocator.DEPENDENT_TEMPLATE makeTypeRef<TypeRefTy>(__VA_ARGS__); \
Allocator.TypeRefTy##s.insert({ID, TR}); \
return TR;
/// An identifier containing the unique bit pattern made up of all of the
/// instance data needed to uniquely identify a TypeRef.
///
/// This allows for uniquing (via Equal) and for keying into a dictionary for
/// caching.
///
/// TypeRefs should be comparable by pointers, so if the TypeRefBuilder
/// gets a request to build a TypeRef with the same constructor arguments,
/// it should return the one already created with those arguments, not a fresh
/// copy. This allows for fast identity comparisons and substitutions, for
/// example. We use a similar strategy for Types in the full AST.
class TypeRefID {
std::vector<uint32_t> Bits;
public:
TypeRefID() = default;
template <typename T>
void addPointer(const T *Pointer) {
auto Raw = reinterpret_cast<uint32_t *>(&Pointer);
Bits.push_back(Raw[0]);
if (sizeof(const T *) > 4) {
Bits.push_back(Raw[1]);
}
}
void addInteger(uint32_t Integer) {
Bits.push_back(Integer);
}
void addInteger(uint64_t Integer) {
Bits.push_back((uint32_t)Integer);
Bits.push_back(Integer >> 32);
}
void addString(const std::string &String) {
if (String.empty()) {
Bits.push_back(0);
} else {
size_t i = 0;
size_t chunks = String.size() / 4;
for (size_t chunk = 0; chunk < chunks; ++chunk, i+=4) {
uint32_t entry = ((uint32_t) String[i]) +
(((uint32_t) String[i+1]) << 8) +
(((uint32_t) String[i+2]) << 16) +
(((uint32_t) String[i+3]) << 24);
Bits.push_back(entry);
}
for (; i < String.size(); ++i) {
Bits.push_back(String[i]);
}
}
}
struct Hash {
std::size_t operator()(TypeRefID const &ID) const {
size_t Hash = 0;
std::hash<uint32_t> h;
for (auto x : ID.Bits) {
Hash ^= h(x) + 0x9e3779b9 + (Hash << 6) + (Hash >> 2);
}
return Hash;
}
};
struct Equal {
bool operator()(const TypeRefID &lhs, const TypeRefID &rhs) const {
return lhs.Bits == rhs.Bits;
}
};
bool operator==(const TypeRefID &Other) {
return Bits == Other.Bits;
}
};
class TypeRef;
class TypeRefBuilder;
using DepthAndIndex = std::pair<unsigned, unsigned>;
using GenericArgumentMap = llvm::DenseMap<DepthAndIndex, const TypeRef *>;
class alignas(void *) TypeRef {
TypeRefKind Kind;
public:
TypeRef(TypeRefKind Kind) : Kind(Kind) {}
TypeRefKind getKind() const {
return Kind;
}
void dump() const;
void dump(std::ostream &OS, unsigned Indent = 0) const;
bool isConcrete() const;
bool isConcreteAfterSubstitutions(const GenericArgumentMap &Subs) const;
const TypeRef *
subst(TypeRefBuilder &Builder, const GenericArgumentMap &Subs) const;
llvm::Optional<GenericArgumentMap> getSubstMap() const;
virtual ~TypeRef() = default;
/// Given an original type and substituted type, decompose them in
/// parallel to derive substitutions that produced the substituted
/// type.
///
/// This will fail if the resulting substitutions contradict already
/// known substitutions, or if the original and substituted types
/// have a structural mismatch.
static bool deriveSubstitutions(GenericArgumentMap &Subs,
const TypeRef *OrigTR,
const TypeRef *SubstTR);
};
class BuiltinTypeRef final : public TypeRef {
std::string MangledName;
static TypeRefID Profile(const std::string &MangledName) {
TypeRefID ID;
ID.addString(MangledName);
return ID;
}
public:
BuiltinTypeRef(const std::string &MangledName)
: TypeRef(TypeRefKind::Builtin), MangledName(MangledName) {}
template <typename Allocator>
static const BuiltinTypeRef *create(Allocator &A, std::string MangledName) {
FIND_OR_CREATE_TYPEREF(A, BuiltinTypeRef, MangledName);
}
const std::string &getMangledName() const {
return MangledName;
}
static bool classof(const TypeRef *TR) {
return TR->getKind() == TypeRefKind::Builtin;
}
};
class NominalTypeTrait {
std::string MangledName;
const TypeRef *Parent;
protected:
static TypeRefID Profile(const std::string &MangledName,
const TypeRef *Parent) {
TypeRefID ID;
ID.addPointer(Parent);
ID.addString(MangledName);
return ID;
}
NominalTypeTrait(const std::string &MangledName, const TypeRef *Parent)
: MangledName(MangledName), Parent(Parent) {}
public:
const std::string &getMangledName() const {
return MangledName;
}
bool isStruct() const;
bool isEnum() const;
bool isClass() const;
bool isProtocol() const;
bool isAlias() const;
bool isErrorProtocol() const {
return MangledName == "s5ErrorP";
}
const TypeRef *getParent() const {
return Parent;
}
unsigned getDepth() const;
};
class NominalTypeRef final : public TypeRef, public NominalTypeTrait {
using NominalTypeTrait::Profile;
public:
NominalTypeRef(const std::string &MangledName,
const TypeRef *Parent = nullptr)
: TypeRef(TypeRefKind::Nominal), NominalTypeTrait(MangledName, Parent) {}
template <typename Allocator>
static const NominalTypeRef *create(Allocator &A,
const std::string &MangledName,
const TypeRef *Parent = nullptr) {
FIND_OR_CREATE_TYPEREF(A, NominalTypeRef, MangledName, Parent);
}
static bool classof(const TypeRef *TR) {
return TR->getKind() == TypeRefKind::Nominal;
}
};
class BoundGenericTypeRef final : public TypeRef, public NominalTypeTrait {
std::vector<const TypeRef *> GenericParams;
static TypeRefID Profile(const std::string &MangledName,
const std::vector<const TypeRef *> &GenericParams,
const TypeRef *Parent) {
TypeRefID ID;
ID.addPointer(Parent);
ID.addString(MangledName);
for (auto Param : GenericParams)
ID.addPointer(Param);
return ID;
}
public:
BoundGenericTypeRef(const std::string &MangledName,
std::vector<const TypeRef *> GenericParams,
const TypeRef *Parent = nullptr)
: TypeRef(TypeRefKind::BoundGeneric),
NominalTypeTrait(MangledName, Parent),
GenericParams(GenericParams) {}
template <typename Allocator>
static const BoundGenericTypeRef *
create(Allocator &A, const std::string &MangledName,
std::vector<const TypeRef *> GenericParams,
const TypeRef *Parent = nullptr) {
FIND_OR_CREATE_TYPEREF(A, BoundGenericTypeRef, MangledName, GenericParams,
Parent);
}
const std::vector<const TypeRef *> &getGenericParams() const {
return GenericParams;
}
static bool classof(const TypeRef *TR) {
return TR->getKind() == TypeRefKind::BoundGeneric;
}
};
class TupleTypeRef final : public TypeRef {
std::vector<const TypeRef *> Elements;
bool Variadic;
static TypeRefID Profile(const std::vector<const TypeRef *> &Elements,
bool Variadic) {
TypeRefID ID;
for (auto Element : Elements)
ID.addPointer(Element);
ID.addInteger(static_cast<uint32_t>(Variadic));
return ID;
}
public:
TupleTypeRef(std::vector<const TypeRef *> Elements, bool Variadic=false)
: TypeRef(TypeRefKind::Tuple), Elements(Elements), Variadic(Variadic) {}
template <typename Allocator>
static const TupleTypeRef *create(Allocator &A,
std::vector<const TypeRef *> Elements,
bool Variadic = false) {
FIND_OR_CREATE_TYPEREF(A, TupleTypeRef, Elements, Variadic);
}
const std::vector<const TypeRef *> &getElements() const {
return Elements;
};
bool isVariadic() const {
return Variadic;
}
static bool classof(const TypeRef *TR) {
return TR->getKind() == TypeRefKind::Tuple;
}
};
class FunctionTypeRef final : public TypeRef {
using Param = remote::FunctionParam<const TypeRef *>;
std::vector<Param> Parameters;
const TypeRef *Result;
FunctionTypeFlags Flags;
static TypeRefID Profile(const std::vector<Param> &Parameters,
const TypeRef *Result, FunctionTypeFlags Flags) {
TypeRefID ID;
for (const auto &Param : Parameters) {
ID.addString(Param.getLabel().str());
ID.addPointer(Param.getType());
ID.addInteger(static_cast<uint32_t>(Param.getFlags().getIntValue()));
}
ID.addPointer(Result);
ID.addInteger(static_cast<uint64_t>(Flags.getIntValue()));
return ID;
}
public:
FunctionTypeRef(std::vector<Param> Params, const TypeRef *Result,
FunctionTypeFlags Flags)
: TypeRef(TypeRefKind::Function), Parameters(Params), Result(Result),
Flags(Flags) {}
template <typename Allocator>
static const FunctionTypeRef *create(Allocator &A, std::vector<Param> Params,
const TypeRef *Result,
FunctionTypeFlags Flags) {
FIND_OR_CREATE_TYPEREF(A, FunctionTypeRef, Params, Result, Flags);
}
const std::vector<Param> &getParameters() const { return Parameters; };
const TypeRef *getResult() const {
return Result;
}
FunctionTypeFlags getFlags() const {
return Flags;
}
static bool classof(const TypeRef *TR) {
return TR->getKind() == TypeRefKind::Function;
}
};
class ProtocolCompositionTypeRef final : public TypeRef {
std::vector<const TypeRef *> Protocols;
const TypeRef *Superclass;
bool HasExplicitAnyObject;
static TypeRefID Profile(std::vector<const TypeRef *> Protocols,
const TypeRef *Superclass,
bool HasExplicitAnyObject) {
TypeRefID ID;
ID.addInteger((uint32_t)HasExplicitAnyObject);
for (auto Protocol : Protocols) {
ID.addPointer(Protocol);
}
ID.addPointer(Superclass);
return ID;
}
public:
ProtocolCompositionTypeRef(std::vector<const TypeRef *> Protocols,
const TypeRef *Superclass,
bool HasExplicitAnyObject)
: TypeRef(TypeRefKind::ProtocolComposition),
Protocols(Protocols), Superclass(Superclass),
HasExplicitAnyObject(HasExplicitAnyObject) {}
template <typename Allocator>
static const ProtocolCompositionTypeRef *
create(Allocator &A, std::vector<const TypeRef *> Protocols,
const TypeRef *Superclass, bool HasExplicitAnyObject) {
FIND_OR_CREATE_TYPEREF(A, ProtocolCompositionTypeRef, Protocols,
Superclass, HasExplicitAnyObject);
}
// These are either NominalTypeRef or ObjCProtocolTypeRef.
const std::vector<const TypeRef *> &getProtocols() const {
return Protocols;
}
const TypeRef *getSuperclass() const { return Superclass; }
bool hasExplicitAnyObject() const {
return HasExplicitAnyObject;
}
static bool classof(const TypeRef *TR) {
return TR->getKind() == TypeRefKind::ProtocolComposition;
}
};
class MetatypeTypeRef final : public TypeRef {
const TypeRef *InstanceType;
bool WasAbstract;
static TypeRefID Profile(const TypeRef *InstanceType, bool WasAbstract) {
TypeRefID ID;
ID.addPointer(InstanceType);
ID.addInteger(static_cast<uint32_t>(WasAbstract));
return ID;
}
public:
MetatypeTypeRef(const TypeRef *InstanceType, bool WasAbstract)
: TypeRef(TypeRefKind::Metatype), InstanceType(InstanceType),
WasAbstract(WasAbstract) {}
template <typename Allocator>
static const MetatypeTypeRef *create(Allocator &A,
const TypeRef *InstanceType,
bool WasAbstract = false) {
FIND_OR_CREATE_TYPEREF(A, MetatypeTypeRef, InstanceType, WasAbstract);
}
bool wasAbstract() const {
return WasAbstract;
}
const TypeRef *getInstanceType() const {
return InstanceType;
}
static bool classof(const TypeRef *TR) {
return TR->getKind() == TypeRefKind::Metatype;
}
};
class ExistentialMetatypeTypeRef final : public TypeRef {
const TypeRef *InstanceType;
static TypeRefID Profile(const TypeRef *InstanceType) {
TypeRefID ID;
ID.addPointer(InstanceType);
return ID;
}
public:
ExistentialMetatypeTypeRef(const TypeRef *InstanceType)
: TypeRef(TypeRefKind::ExistentialMetatype), InstanceType(InstanceType) {}
template <typename Allocator>
static const ExistentialMetatypeTypeRef *
create(Allocator &A, const TypeRef *InstanceType) {
FIND_OR_CREATE_TYPEREF(A, ExistentialMetatypeTypeRef, InstanceType);
}
const TypeRef *getInstanceType() const {
return InstanceType;
}
static bool classof(const TypeRef *TR) {
return TR->getKind() == TypeRefKind::ExistentialMetatype;
}
};
class GenericTypeParameterTypeRef final : public TypeRef {
const uint32_t Depth;
const uint32_t Index;
static TypeRefID Profile(uint32_t Depth, uint32_t Index) {
TypeRefID ID;
ID.addInteger(Depth);
ID.addInteger(Index);
return ID;
}
public:
GenericTypeParameterTypeRef(uint32_t Depth, uint32_t Index)
: TypeRef(TypeRefKind::GenericTypeParameter), Depth(Depth), Index(Index) {}
template <typename Allocator>
static const GenericTypeParameterTypeRef *
create(Allocator &A, uint32_t Depth, uint32_t Index) {
FIND_OR_CREATE_TYPEREF(A, GenericTypeParameterTypeRef, Depth, Index);
}
uint32_t getDepth() const {
return Depth;
}
uint32_t getIndex() const {
return Index;
}
static bool classof(const TypeRef *TR) {
return TR->getKind() == TypeRefKind::GenericTypeParameter;
}
};
class DependentMemberTypeRef final : public TypeRef {
std::string Member;
const TypeRef *Base;
std::string Protocol;
static TypeRefID Profile(const std::string &Member, const TypeRef *Base,
const std::string &Protocol) {
TypeRefID ID;
ID.addString(Member);
ID.addPointer(Base);
ID.addString(Protocol);
return ID;
}
public:
DependentMemberTypeRef(const std::string &Member, const TypeRef *Base,
const std::string &Protocol)
: TypeRef(TypeRefKind::DependentMember), Member(Member), Base(Base),
Protocol(Protocol) {}
template <typename Allocator>
static const DependentMemberTypeRef *
create(Allocator &A, const std::string &Member,
const TypeRef *Base, const std::string &Protocol) {
FIND_OR_CREATE_TYPEREF(A, DependentMemberTypeRef, Member, Base, Protocol);
}
const std::string &getMember() const {
return Member;
}
const TypeRef *getBase() const {
return Base;
}
const std::string &getProtocol() const {
return Protocol;
}
static bool classof(const TypeRef *TR) {
return TR->getKind() == TypeRefKind::DependentMember;
}
};
class ForeignClassTypeRef final : public TypeRef {
std::string Name;
static TypeRefID Profile(const std::string &Name) {
TypeRefID ID;
ID.addString(Name);
return ID;
}
public:
ForeignClassTypeRef(const std::string &Name)
: TypeRef(TypeRefKind::ForeignClass), Name(Name) {}
template <typename Allocator>
static const ForeignClassTypeRef *create(Allocator &A,
const std::string &Name) {
FIND_OR_CREATE_TYPEREF(A, ForeignClassTypeRef, Name);
}
const std::string &getName() const {
return Name;
}
static bool classof(const TypeRef *TR) {
return TR->getKind() == TypeRefKind::ForeignClass;
}
};
class ObjCClassTypeRef final : public TypeRef {
std::string Name;
static const ObjCClassTypeRef *UnnamedSingleton;
static TypeRefID Profile(const std::string &Name) {
TypeRefID ID;
ID.addString(Name);
return ID;
}
public:
ObjCClassTypeRef(const std::string &Name)
: TypeRef(TypeRefKind::ObjCClass), Name(Name) {}
static const ObjCClassTypeRef *getUnnamed();
template <typename Allocator>
static const ObjCClassTypeRef *create(Allocator &A, const std::string &Name) {
FIND_OR_CREATE_TYPEREF(A, ObjCClassTypeRef, Name);
}
const std::string &getName() const {
return Name;
}
static bool classof(const TypeRef *TR) {
return TR->getKind() == TypeRefKind::ObjCClass;
}
};
class ObjCProtocolTypeRef final : public TypeRef {
std::string Name;
static const ObjCProtocolTypeRef *UnnamedSingleton;
static TypeRefID Profile(const std::string &Name) {
TypeRefID ID;
ID.addString(Name);
return ID;
}
public:
ObjCProtocolTypeRef(const std::string &Name)
: TypeRef(TypeRefKind::ObjCProtocol), Name(Name) {}
static const ObjCProtocolTypeRef *getUnnamed();
template <typename Allocator>
static const ObjCProtocolTypeRef *create(Allocator &A,
const std::string &Name) {
FIND_OR_CREATE_TYPEREF(A, ObjCProtocolTypeRef, Name);
}
const std::string &getName() const {
return Name;
}
static bool classof(const TypeRef *TR) {
return TR->getKind() == TypeRefKind::ObjCProtocol;
}
};
class OpaqueTypeRef final : public TypeRef {
static const OpaqueTypeRef *Singleton;
OpaqueTypeRef() : TypeRef(TypeRefKind::Opaque) {}
static TypeRefID Profile() {
return TypeRefID();
}
public:
static const OpaqueTypeRef *get();
static bool classof(const TypeRef *TR) {
return TR->getKind() == TypeRefKind::Opaque;
}
};
class ReferenceStorageTypeRef : public TypeRef {
const TypeRef *Type;
protected:
ReferenceStorageTypeRef(TypeRefKind Kind, const TypeRef *Type)
: TypeRef(Kind), Type(Type) {}
static TypeRefID Profile(const TypeRef *Type) {
TypeRefID ID;
ID.addPointer(Type);
return ID;
}
public:
const TypeRef *getType() const {
return Type;
}
static bool classof(const TypeRef *TR) {
switch (TR->getKind()) {
#define REF_STORAGE(Name, ...) \
case TypeRefKind::Name##Storage:
#include "swift/AST/ReferenceStorage.def"
return true;
default:
return false;
}
}
};
#define REF_STORAGE(Name, ...) \
class Name##StorageTypeRef final : public ReferenceStorageTypeRef { \
using ReferenceStorageTypeRef::Profile; \
public: \
Name##StorageTypeRef(const TypeRef *Type) \
: ReferenceStorageTypeRef(TypeRefKind::Name##Storage, Type) {} \
template <typename Allocator> \
static const Name##StorageTypeRef *create(Allocator &A, \
const TypeRef *Type) { \
FIND_OR_CREATE_TYPEREF(A, Name##StorageTypeRef, Type); \
} \
static bool classof(const TypeRef *TR) { \
return TR->getKind() == TypeRefKind::Name##Storage; \
} \
};
#include "swift/AST/ReferenceStorage.def"
class SILBoxTypeRef final : public TypeRef {
const TypeRef *BoxedType;
static TypeRefID Profile(const TypeRef *BoxedType) {
TypeRefID ID;
ID.addPointer(BoxedType);
return ID;
}
public:
SILBoxTypeRef(const TypeRef *BoxedType)
: TypeRef(TypeRefKind::SILBox), BoxedType(BoxedType) {}
template <typename Allocator>
static const SILBoxTypeRef *create(Allocator &A,
const TypeRef *BoxedType) {
FIND_OR_CREATE_TYPEREF(A, SILBoxTypeRef, BoxedType);
}
const TypeRef *getBoxedType() const {
return BoxedType;
}
static bool classof(const TypeRef *TR) {
return TR->getKind() == TypeRefKind::SILBox;
}
};
template <typename ImplClass, typename RetTy = void, typename... Args>
class TypeRefVisitor {
public:
RetTy visit(const TypeRef *typeRef, Args... args) {
switch (typeRef->getKind()) {
#define TYPEREF(Id, Parent) \
case TypeRefKind::Id: \
return static_cast<ImplClass*>(this) \
->visit##Id##TypeRef(cast<Id##TypeRef>(typeRef), \
::std::forward<Args>(args)...);
#include "swift/Reflection/TypeRefs.def"
}
swift_runtime_unreachable("Unhandled TypeRefKind in switch.");
}
};
} // end namespace reflection
} // end namespace swift
#endif // SWIFT_REFLECTION_TYPEREF_H