blob: fccbe06bde122858885a571c5f9839ac1c1fabd9 [file] [log] [blame]
//===--- GenericSignature.h - Generic Signature AST -------------*- 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
//
//===----------------------------------------------------------------------===//
//
// This file defines the GenericSignature class and its related classes.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_AST_GENERIC_SIGNATURE_H
#define SWIFT_AST_GENERIC_SIGNATURE_H
#include "swift/AST/PrintOptions.h"
#include "swift/AST/Requirement.h"
#include "swift/AST/Type.h"
#include "swift/AST/TypeAlignments.h"
#include "swift/Basic/AnyValue.h"
#include "swift/Basic/Debug.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/TrailingObjects.h"
#include <utility>
namespace swift {
class GenericSignatureBuilder;
class ProtocolConformanceRef;
class ProtocolType;
class SubstitutionMap;
class GenericEnvironment;
/// An access path used to find a particular protocol conformance within
/// a generic signature.
///
/// One can follow a conformance path to extract any conformance that is
/// derivable within the generic signature. For example, given:
///
/// \code
/// func f<C: Collection>(_: C) where C.Iterator.Element: Hashable { }
/// \endcode
///
/// One can extract conformances for various types and protocols, including
/// those written directly (\c C: Collection, \c C.Iterator.Element: Hashable),
/// and others that can be derived (\c C: Sequence,
/// \c C.Iterator: IteratorProtocol, \c C.Iterator.Element: Equatable).
///
/// A conformance access path is a sequence of (dependent type, protocol decl)
/// pairs that starts at an explicit requirement in the generic signature
/// (e.g., \c C: Collection). Each subsequent step names a dependent
/// type and protocol that refers to an explicit requirement in the requirement
/// signature of the previous step's protocol. For example, consider the
/// derived conformance \c C.Iterator: IteratorProtocol, which has the
/// following path:
///
/// \code
/// (C, Collection) -> (Self, Sequence) -> (Self.Iterator, IteratorProtocol)
/// \endcode
///
/// Therefore, the path starts at \c C: Collection. It then retrieves the
/// \c Sequence conformance of \c C (because \c Collection inherits
/// \c Sequence). Finally, it extracts the conformance of the associated type
/// \c Iterator to \c IteratorProtocol from the \c Sequence protocol.
class ConformanceAccessPath {
public:
/// An entry in the conformance access path, which is described by the
/// dependent type on which the conformance is stated as the protocol to
/// which.
typedef std::pair<Type, ProtocolDecl *> Entry;
private:
ArrayRef<Entry> path;
ConformanceAccessPath(ArrayRef<Entry> path) : path(path) {}
friend class GenericSignatureImpl;
public:
typedef const Entry *const_iterator;
typedef const_iterator iterator;
const_iterator begin() const { return path.begin(); }
const_iterator end() const { return path.end(); }
void print(raw_ostream &OS) const;
SWIFT_DEBUG_DUMP;
};
class CanGenericSignature;
class GenericSignatureImpl;
class GenericTypeParamType;
/// Describes the generic signature of a particular declaration, including
/// both the generic type parameters and the requirements placed on those
/// generic parameters.
class GenericSignature {
const GenericSignatureImpl *Ptr;
public:
/// Create a new generic signature with the given type parameters and
/// requirements.
static GenericSignature get(ArrayRef<GenericTypeParamType *> params,
ArrayRef<Requirement> requirements,
bool isKnownCanonical = false);
static GenericSignature get(TypeArrayView<GenericTypeParamType> params,
ArrayRef<Requirement> requirements,
bool isKnownCanonical = false);
public:
static ASTContext &getASTContext(TypeArrayView<GenericTypeParamType> params,
ArrayRef<Requirement> requirements);
public:
/*implicit*/ GenericSignature(const GenericSignatureImpl *P = 0) : Ptr(P) {}
const GenericSignatureImpl *getPointer() const { return Ptr; }
bool isNull() const { return Ptr == 0; }
const GenericSignatureImpl *operator->() const {
assert(Ptr && "Cannot dereference a null GenericSignature!");
return Ptr;
}
explicit operator bool() const { return Ptr != 0; }
/// Whether the given set of requirements involves a type variable.
static bool hasTypeVariable(ArrayRef<Requirement> requirements);
friend llvm::hash_code hash_value(GenericSignature sig) {
using llvm::hash_value;
return hash_value(sig.getPointer());
}
void print(raw_ostream &OS,
const PrintOptions &Options = PrintOptions()) const;
void print(ASTPrinter &Printer,
const PrintOptions &Opts = PrintOptions()) const;
SWIFT_DEBUG_DUMP;
std::string getAsString() const;
/// Returns the canonical generic signature, or \c nullptr if the underlying
/// pointer is \c nullptr. The result is cached.
CanGenericSignature getCanonicalSignature() const;
// Support for FoldingSet.
void Profile(llvm::FoldingSetNodeID &id) const;
static void Profile(llvm::FoldingSetNodeID &ID,
TypeArrayView<GenericTypeParamType> genericParams,
ArrayRef<Requirement> requirements);
public:
using RequiredProtocols = SmallVector<ProtocolDecl *, 2>;
private:
// Direct comparison is disabled for generic signatures. Canonicalize them
// first, or use isEqual.
void operator==(GenericSignature T) const = delete;
void operator!=(GenericSignature T) const = delete;
};
/// A reference to a canonical generic signature.
class CanGenericSignature : public GenericSignature {
bool isActuallyCanonicalOrNull() const;
public:
/// Create a new generic signature with the given type parameters and
/// requirements, first canonicalizing the types.
static CanGenericSignature
getCanonical(TypeArrayView<GenericTypeParamType> params,
ArrayRef<Requirement> requirements, bool skipValidation = false);
public:
CanGenericSignature(std::nullptr_t) : GenericSignature(nullptr) {}
explicit CanGenericSignature(const GenericSignatureImpl *P = 0)
: GenericSignature(P) {
assert(isActuallyCanonicalOrNull() &&
"Forming a CanGenericSignature out of a non-canonical signature!");
}
explicit CanGenericSignature(GenericSignature S) : GenericSignature(S) {
assert(isActuallyCanonicalOrNull() &&
"Forming a CanGenericSignature out of a non-canonical signature!");
}
ArrayRef<CanTypeWrapper<GenericTypeParamType>> getGenericParams() const;
bool operator==(CanGenericSignature S) const {
return getPointer() == S.getPointer();
}
bool operator!=(CanGenericSignature S) const { return !operator==(S); }
};
/// The underlying implementation of generic signatures.
class alignas(1 << TypeAlignInBits) GenericSignatureImpl final
: public llvm::FoldingSetNode,
private llvm::TrailingObjects<GenericSignatureImpl, Type, Requirement> {
friend class ASTContext;
friend GenericSignature;
friend TrailingObjects;
GenericSignatureImpl(const GenericSignatureImpl&) = delete;
void operator=(const GenericSignatureImpl&) = delete;
const unsigned NumGenericParams;
const unsigned NumRequirements;
GenericEnvironment *GenericEnv = nullptr;
// Make vanilla new/delete illegal.
void *operator new(size_t Bytes) = delete;
void operator delete(void *Data) = delete;
size_t numTrailingObjects(OverloadToken<Type>) const {
return NumGenericParams;
}
size_t numTrailingObjects(OverloadToken<Requirement>) const {
return NumRequirements;
}
GenericSignatureImpl(TypeArrayView<GenericTypeParamType> params,
ArrayRef<Requirement> requirements,
bool isKnownCanonical);
// FIXME: Making this a CanGenericSignature reveals callers are violating
// the interface's invariants.
mutable llvm::PointerUnion<const GenericSignatureImpl *, ASTContext *>
CanonicalSignatureOrASTContext;
void buildConformanceAccessPath(
SmallVectorImpl<ConformanceAccessPath::Entry> &path,
ArrayRef<Requirement> reqs,
const void /*GenericSignatureBuilder::RequirementSource*/ *source,
ProtocolDecl *conformingProto, Type rootType,
ProtocolDecl *requirementSignatureProto) const;
friend class ArchetypeType;
public:
/// Retrieve the generic parameters.
TypeArrayView<GenericTypeParamType> getGenericParams() const {
return TypeArrayView<GenericTypeParamType>(
{getTrailingObjects<Type>(), NumGenericParams});
}
/// Retrieve the innermost generic parameters.
///
/// Given a generic signature for a nested generic type, produce an
/// array of the generic parameters for the innermost generic type.
TypeArrayView<GenericTypeParamType> getInnermostGenericParams() const;
/// Retrieve the requirements.
ArrayRef<Requirement> getRequirements() const {
return {getTrailingObjects<Requirement>(), NumRequirements};
}
/// Only allow allocation by doing a placement new.
void *operator new(size_t Bytes, void *Mem) {
assert(Mem);
return Mem;
}
/// Look up a stored conformance in the generic signature. These are formed
/// from same-type constraints placed on associated types of generic
/// parameters which have conformance constraints on them.
ProtocolConformanceRef lookupConformance(CanType depTy,
ProtocolDecl *proto) const;
/// Iterate over all generic parameters, passing a flag to the callback
/// indicating if the generic parameter is canonical or not.
void forEachParam(
llvm::function_ref<void(GenericTypeParamType *, bool)> callback) const;
/// Check if the generic signature makes all generic parameters
/// concrete.
bool areAllParamsConcrete() const;
/// Compute the number of conformance requirements in this signature.
unsigned getNumConformanceRequirements() const {
unsigned result = 0;
for (const auto &req : getRequirements()) {
if (req.getKind() == RequirementKind::Conformance)
++result;
}
return result;
}
/// Return true if these two generic signatures are equal.
bool isEqual(GenericSignature Other) const;
/// Determines whether this GenericSignature is canonical.
bool isCanonical() const;
ASTContext &getASTContext() const;
/// Returns the canonical generic signature. The result is cached.
CanGenericSignature getCanonicalSignature() const;
/// Retrieve the generic signature builder for the given generic signature.
GenericSignatureBuilder *getGenericSignatureBuilder() const;
/// Returns the generic environment that provides fresh contextual types
/// (archetypes) that correspond to the interface types in this generic
/// signature.
GenericEnvironment *getGenericEnvironment() const;
/// Uniquing for the ASTContext.
void Profile(llvm::FoldingSetNodeID &ID) const {
Profile(ID, getGenericParams(), getRequirements());
}
/// Determine whether the given dependent type is required to be a class.
bool requiresClass(Type type) const;
/// Determine the superclass bound on the given dependent type.
Type getSuperclassBound(Type type) const;
/// Determine the set of protocols to which the given type parameter is
/// required to conform.
GenericSignature::RequiredProtocols getRequiredProtocols(Type type) const;
/// Determine whether the given type parameter is required to conform to
/// the given protocol.
bool requiresProtocol(Type type, ProtocolDecl *proto) const;
/// Determine whether the given dependent type is equal to a concrete type.
bool isConcreteType(Type type) const;
/// Return the concrete type that the given type parameter is constrained to,
/// or the null Type if it is not the subject of a concrete same-type
/// constraint.
Type getConcreteType(Type type) const;
/// Return the layout constraint that the given type parameter is constrained
/// to, or the null LayoutConstraint if it is not the subject of layout
/// constraint.
LayoutConstraint getLayoutConstraint(Type type) const;
/// Return whether two type parameters represent the same type under this
/// generic signature.
///
/// The type parameters must be known to not be concrete within the context.
bool areSameTypeParameterInContext(Type type1, Type type2) const;
/// Determine if \c sig can prove \c requirement, meaning that it can deduce
/// T: Foo or T == U (etc.) with the information it knows. This includes
/// checking against global state, if any/all of the types in the requirement
/// are concrete, not type parameters.
bool isRequirementSatisfied(Requirement requirement) const;
/// Return the requirements of this generic signature that are not also
/// satisfied by \c otherSig.
///
/// \param otherSig Another generic signature whose generic parameters are
/// equivalent to or a subset of the generic parameters in this signature.
SmallVector<Requirement, 4> requirementsNotSatisfiedBy(
GenericSignature otherSig) const;
/// Return the canonical version of the given type under this generic
/// signature.
CanType getCanonicalTypeInContext(Type type) const;
bool isCanonicalTypeInContext(Type type) const;
/// Return the canonical version of the given type under this generic
/// signature.
CanType getCanonicalTypeInContext(Type type,
GenericSignatureBuilder &builder) const;
bool isCanonicalTypeInContext(Type type,
GenericSignatureBuilder &builder) const;
/// Retrieve the conformance access path used to extract the conformance of
/// interface \c type to the given \c protocol.
///
/// \param type The interface type whose conformance access path is to be
/// queried.
/// \param protocol A protocol to which \c type conforms.
///
/// \returns the conformance access path that starts at a requirement of
/// this generic signature and ends at the conformance that makes \c type
/// conform to \c protocol.
///
/// \seealso ConformanceAccessPath
ConformanceAccessPath getConformanceAccessPath(Type type,
ProtocolDecl *protocol) const;
/// Get the ordinal of a generic parameter in this generic signature.
///
/// For example, if you have a generic signature for a nested context like:
/// <t_0_0, t_0_1, t_1_0>
/// then this will return 0 for t_0_0, 1 for t_0_1, and 2 for t_1_0.
unsigned getGenericParamOrdinal(GenericTypeParamType *param) const;
/// Get a substitution map that maps all of the generic signature's
/// generic parameters to themselves.
SubstitutionMap getIdentitySubstitutionMap() const;
/// Get the sugared form of a generic parameter type.
GenericTypeParamType *getSugaredType(GenericTypeParamType *type) const;
/// Get the sugared form of a type by substituting any
/// generic parameter types by their sugared form.
Type getSugaredType(Type type) const;
/// Whether this generic signature involves a type variable.
bool hasTypeVariable() const;
static void Profile(llvm::FoldingSetNodeID &ID,
TypeArrayView<GenericTypeParamType> genericParams,
ArrayRef<Requirement> requirements);
void print(raw_ostream &OS, PrintOptions Options = PrintOptions()) const;
void print(ASTPrinter &Printer, PrintOptions Opts = PrintOptions()) const;
SWIFT_DEBUG_DUMP;
std::string getAsString() const;
};
void simple_display(raw_ostream &out, GenericSignature sig);
inline bool CanGenericSignature::isActuallyCanonicalOrNull() const {
return getPointer() == nullptr ||
getPointer() ==
llvm::DenseMapInfo<GenericSignatureImpl *>::getEmptyKey() ||
getPointer() ==
llvm::DenseMapInfo<GenericSignatureImpl *>::getTombstoneKey() ||
getPointer()->isCanonical();
}
} // end namespace swift
namespace llvm {
static inline raw_ostream &operator<<(raw_ostream &OS,
swift::GenericSignature Sig) {
Sig.print(OS);
return OS;
}
// A GenericSignature casts like a GenericSignatureImpl*.
template <> struct simplify_type<const ::swift::GenericSignature> {
typedef const ::swift::GenericSignatureImpl *SimpleType;
static SimpleType getSimplifiedValue(const ::swift::GenericSignature &Val) {
return Val.getPointer();
}
};
template <>
struct simplify_type<::swift::GenericSignature>
: public simplify_type<const ::swift::GenericSignature> {};
template <> struct DenseMapInfo<swift::GenericSignature> {
static swift::GenericSignature getEmptyKey() {
return llvm::DenseMapInfo<swift::GenericSignatureImpl *>::getEmptyKey();
}
static swift::GenericSignature getTombstoneKey() {
return llvm::DenseMapInfo<swift::GenericSignatureImpl *>::getTombstoneKey();
}
static unsigned getHashValue(swift::GenericSignature Val) {
return DenseMapInfo<swift::GenericSignatureImpl *>::getHashValue(
Val.getPointer());
}
static bool isEqual(swift::GenericSignature LHS,
swift::GenericSignature RHS) {
return LHS.getPointer() == RHS.getPointer();
}
};
// A GenericSignature is "pointer like".
template <> struct PointerLikeTypeTraits<swift::GenericSignature> {
public:
static inline swift::GenericSignature getFromVoidPointer(void *P) {
return (swift::GenericSignatureImpl *)P;
}
static inline void *getAsVoidPointer(swift::GenericSignature S) {
return (void *)S.getPointer();
}
enum { NumLowBitsAvailable = swift::TypeAlignInBits };
};
template <> struct PointerLikeTypeTraits<swift::CanGenericSignature> {
public:
static inline swift::CanGenericSignature getFromVoidPointer(void *P) {
return swift::CanGenericSignature((swift::GenericSignatureImpl *)P);
}
static inline void *getAsVoidPointer(swift::CanGenericSignature S) {
return (void *)S.getPointer();
}
enum { NumLowBitsAvailable = swift::TypeAlignInBits };
};
} // end namespace llvm
#endif // SWIFT_AST_GENERIC_SIGNATURE_H