blob: d6e15be93c20f83d96427e962d8337ef592fec2c [file] [log] [blame]
//===--- TypeLowering.h - Convert Swift Types to SILTypes -------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_SIL_TYPELOWERING_H
#define SWIFT_SIL_TYPELOWERING_H
#include "swift/AST/CaptureInfo.h"
#include "swift/ABI/MetadataValues.h"
#include "swift/SIL/AbstractionPattern.h"
#include "swift/SIL/SILLocation.h"
#include "swift/SIL/SILValue.h"
#include "swift/SIL/SILDeclRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Allocator.h"
namespace clang {
class Type;
}
namespace swift {
class AnyFunctionRef;
class ForeignErrorConvention;
enum IsInitialization_t : bool;
enum IsTake_t : bool;
class SILBuilder;
class SILLocation;
class SILModule;
class ValueDecl;
namespace Lowering {
/// The default convention for handling the callee object on thick
/// callees.
const ParameterConvention DefaultThickCalleeConvention =
ParameterConvention::Direct_Owned;
/// Given an AST function type, return a type that is identical except
/// for using the given ExtInfo.
CanAnyFunctionType adjustFunctionType(CanAnyFunctionType type,
AnyFunctionType::ExtInfo extInfo);
/// Change the given function type's representation.
inline CanAnyFunctionType adjustFunctionType(CanAnyFunctionType t,
SILFunctionType::Representation rep) {
auto extInfo = t->getExtInfo().withSILRepresentation(rep);
return adjustFunctionType(t, extInfo);
}
/// Change the given function type's representation.
inline CanAnyFunctionType adjustFunctionType(CanAnyFunctionType t,
AnyFunctionType::Representation rep) {
auto extInfo = t->getExtInfo().withRepresentation(rep);
return adjustFunctionType(t, extInfo);
}
/// Given a SIL function type, return a type that is identical except
/// for using the given ExtInfo.
CanSILFunctionType adjustFunctionType(CanSILFunctionType type,
SILFunctionType::ExtInfo extInfo,
ParameterConvention calleeConv);
inline CanSILFunctionType adjustFunctionType(CanSILFunctionType type,
SILFunctionType::ExtInfo extInfo) {
return adjustFunctionType(type, extInfo, type->getCalleeConvention());
}
inline CanSILFunctionType adjustFunctionType(CanSILFunctionType t,
SILFunctionType::Representation rep) {
if (t->getRepresentation() == rep) return t;
auto extInfo = t->getExtInfo().withRepresentation(rep);
return adjustFunctionType(t, extInfo,
extInfo.hasContext() ? DefaultThickCalleeConvention
: ParameterConvention::Direct_Unowned);
}
/// Flag used to place context-dependent TypeLowerings in their own arena which
/// can be disposed when a generic context is exited.
enum IsDependent_t : unsigned {
IsNotDependent = false,
IsDependent = true
};
/// Extended type information used by SIL.
class TypeLowering {
public:
enum IsTrivial_t : bool { IsNotTrivial, IsTrivial };
enum IsAddressOnly_t : bool { IsNotAddressOnly, IsAddressOnly };
enum IsReferenceCounted_t : bool {
IsNotReferenceCounted,
IsReferenceCounted
};
private:
/// The SIL type of values with this Swift type.
SILType LoweredType;
enum : unsigned {
IsTrivialFlag = 0x1,
IsAddressOnlyFlag = 0x2,
IsReferenceCountedFlag = 0x4,
};
unsigned Flags;
protected:
TypeLowering(SILType type, IsTrivial_t isTrivial,
IsAddressOnly_t isAddressOnly,
IsReferenceCounted_t isRefCounted)
: LoweredType(type), Flags((isTrivial ? IsTrivialFlag : 0U) |
(isAddressOnly ? IsAddressOnlyFlag : 0U) |
(isRefCounted ? IsReferenceCountedFlag : 0U)) {}
public:
TypeLowering(const TypeLowering &) = delete;
TypeLowering &operator=(const TypeLowering &) = delete;
virtual ~TypeLowering() {}
/// \brief Are r-values of this type passed as arguments indirectly?
bool isPassedIndirectly() const {
return isAddressOnly();
}
/// \brief Are r-values of this type returned indirectly?
bool isReturnedIndirectly() const {
return isAddressOnly();
}
/// isAddressOnly - Returns true if the type is an address-only type. A type
/// is address-only if it is a resilient value type, or if it is a fragile
/// value type with a resilient member. In either case, the full layout of
/// values of the type is unavailable to the compiler.
bool isAddressOnly() const {
return Flags & IsAddressOnlyFlag;
}
/// isLoadable - Returns true if the type is loadable, in other words, its
/// full layout is available to the compiler. This is the inverse of
/// isAddressOnly.
bool isLoadable() const {
return !isAddressOnly();
}
/// Returns true if the type is trivial, meaning it is a loadable
/// value type with no reference type members that require releasing.
bool isTrivial() const {
return Flags & IsTrivialFlag;
}
/// Returns true if the type is a scalar reference-counted reference, which
/// can be retained and released.
bool isReferenceCounted() const {
return Flags & IsReferenceCountedFlag;
}
/// getLoweredType - Get the type used to represent values of the Swift type
/// in SIL.
SILType getLoweredType() const {
return LoweredType;
}
/// Return the semantic type.
///
/// The semantic type is what a type pretends to be during
/// type-checking: that is, the type that getTypeOfRValue would
/// return on a variable of this type.
SILType getSemanticType() const {
// If you change this, change getSemanticTypeLowering() too.
auto storageType = getLoweredType().getSwiftRValueType();
if (auto refType = dyn_cast<ReferenceStorageType>(storageType))
return SILType::getPrimitiveType(refType.getReferentType(),
SILValueCategory::Object);
return getLoweredType();
}
/// Return the lowering for the semantic type.
inline const TypeLowering &getSemanticTypeLowering(TypeConverter &TC) const;
/// Produce an exact copy of the value in the given address as a
/// scalar. The caller is responsible for destroying this value,
/// e.g. by releasing it.
///
/// This type must be loadable.
virtual SILValue emitLoadOfCopy(SILBuilder &B,
SILLocation loc,
SILValue addr,
IsTake_t isTake) const = 0;
/// Store an exact copy of the given value in the destination
/// address, taking ownership of it.
///
/// This type must be loadable.
///
/// Note that, for an assignment, this produces lowered code: that
/// is, for non-POD types, an explicit load and release. Therefore,
/// it is generally not correct to call this during SIL-gen.
virtual void emitStoreOfCopy(SILBuilder &B,
SILLocation loc,
SILValue value,
SILValue addr,
IsInitialization_t isInit) const = 0;
/// Put an exact copy of the value in the source address in the
/// destination address.
virtual void emitCopyInto(SILBuilder &B,
SILLocation loc,
SILValue src,
SILValue dest,
IsTake_t isTake,
IsInitialization_t isInit) const = 0;
/// Given an address, emit operations to destroy it.
///
/// This produces canonicalized SIL.
virtual void emitDestroyAddress(SILBuilder &B, SILLocation loc,
SILValue value) const = 0;
/// Given a +1 r-value which we are claiming ownership of, destroy it.
///
/// Note that an r-value might be an address.
virtual void emitDestroyRValue(SILBuilder &B, SILLocation loc,
SILValue value) const = 0;
enum class LoweringStyle {
Shallow,
DeepNoEnum
};
/// Emit a lowered 'release_value' operation.
///
/// This type must be loadable.
virtual void emitLoweredDestroyValue(SILBuilder &B, SILLocation loc,
SILValue value,
LoweringStyle loweringStyle) const = 0;
void emitLoweredDestroyChildValue(SILBuilder &B, SILLocation loc,
SILValue value,
LoweringStyle loweringStyle) const {
if (loweringStyle != LoweringStyle::Shallow)
return emitLoweredDestroyValue(B, loc, value, loweringStyle);
return emitDestroyValue(B, loc, value);
}
/// Emit a lowered 'release_value' operation.
///
/// This type must be loadable.
void emitLoweredDestroyValueShallow(SILBuilder &B, SILLocation loc,
SILValue value) const {
emitLoweredDestroyValue(B, loc, value, LoweringStyle::Shallow);
}
/// Emit a lowered 'release_value' operation.
///
/// This type must be loadable.
void emitLoweredDestroyValueDeepNoEnum(SILBuilder &B, SILLocation loc,
SILValue value) const {
emitLoweredDestroyValue(B, loc, value, LoweringStyle::DeepNoEnum);
}
/// Given a primitively loaded value of this type (which must be
/// loadable), -1 it.
///
/// This should be used when dropping a value which has been copied
/// from place to place with exactly the same semantics. For
/// example, it performs an unowned_release on a value of [unknown]
/// type. It is therefore not necessarily the right thing to do on
/// a semantic load.
virtual void emitDestroyValue(SILBuilder &B, SILLocation loc,
SILValue value) const = 0;
/// Emit a lowered 'retain_value' operation.
///
/// This type must be loadable.
virtual void emitLoweredCopyValue(SILBuilder &B, SILLocation loc,
SILValue value,
LoweringStyle style) const = 0;
/// Emit a lowered 'retain_value' operation.
///
/// This type must be loadable.
void emitLoweredCopyValueShallow(SILBuilder &B, SILLocation loc,
SILValue value) const {
emitLoweredCopyValue(B, loc, value, LoweringStyle::Shallow);
}
/// Emit a lowered 'retain_value' operation.
///
/// This type must be loadable.
void emitLoweredRetainValueDeepNoEnum(SILBuilder &B, SILLocation loc,
SILValue value) const {
emitLoweredCopyValue(B, loc, value, LoweringStyle::DeepNoEnum);
}
/// Given a primitively loaded value of this type (which must be
/// loadable), +1 it.
///
/// This should be used for duplicating a value from place to place
/// with exactly the same semantics. For example, it performs an
/// unowned_retain on a value of [unknown] type. It is therefore
/// not necessarily the right thing to do on a semantic load.
virtual void emitCopyValue(SILBuilder &B, SILLocation loc,
SILValue value) const = 0;
void emitLoweredCopyChildValue(SILBuilder &B, SILLocation loc,
SILValue value,
LoweringStyle style) const {
if (style != LoweringStyle::Shallow) {
emitLoweredCopyValue(B, loc, value, style);
} else {
emitCopyValue(B, loc, value);
}
}
/// Allocate a new TypeLowering using the TypeConverter's allocator.
void *operator new(size_t size, TypeConverter &tc,
IsDependent_t dependent);
void *operator new[](size_t size, TypeConverter &tc,
IsDependent_t dependent);
// Forbid 'new FooTypeLowering' and try to forbid 'delete tl'.
// The latter is made challenging because the existence of the
// virtual destructor requires an accessible 'operator delete'.
void *operator new(size_t) = delete;
protected:
void operator delete(void*) {}
};
/// Type and lowering information about a constant function.
struct SILConstantInfo {
/// The formal type of the constant, still curried. For a normal
/// function, this is just its declared type; for a getter or
/// setter, computing this can be more involved.
CanAnyFunctionType FormalInterfaceType;
/// The uncurried and bridged type of the constant.
CanAnyFunctionType LoweredInterfaceType;
/// The SIL function type of the constant.
CanSILFunctionType SILFnType;
/// The generic environment used by the constant.
GenericEnvironment *GenericEnv;
SILType getSILType() const {
return SILType::getPrimitiveObjectType(SILFnType);
}
friend bool operator==(SILConstantInfo lhs, SILConstantInfo rhs) {
return lhs.FormalInterfaceType == rhs.FormalInterfaceType &&
lhs.LoweredInterfaceType == rhs.LoweredInterfaceType &&
lhs.SILFnType == rhs.SILFnType &&
lhs.GenericEnv == rhs.GenericEnv;
}
friend bool operator!=(SILConstantInfo lhs, SILConstantInfo rhs) {
return !(lhs == rhs);
}
};
/// Different ways in which a function can capture context.
enum class CaptureKind {
/// No context arguments are necessary.
None,
/// A local value captured as a mutable box.
Box,
/// A local value captured as a single pointer to storage (formed with
/// @noescape closures).
StorageAddress,
/// A local value captured as a constant.
Constant,
};
/// TypeConverter - helper class for creating and managing TypeLowerings.
class TypeConverter {
friend class TypeLowering;
llvm::BumpPtrAllocator IndependentBPA;
/// BumpPtrAllocator for types dependent on contextual generic parameters,
/// which is reset when the generic context is popped.
llvm::BumpPtrAllocator DependentBPA;
enum : unsigned {
/// There is a unique entry with this uncurry level in the
/// type-lowering map for every TLI we create. The map has the
/// responsibility to call the destructor for these entries.
UniqueLoweringEntry = ~0U
};
struct CachingTypeKey {
GenericSignature *Sig;
AbstractionPattern::CachingKey OrigType;
CanType SubstType;
unsigned UncurryLevel;
friend bool operator==(const CachingTypeKey &lhs,
const CachingTypeKey &rhs) {
return lhs.Sig == rhs.Sig
&& lhs.OrigType == rhs.OrigType
&& lhs.SubstType == rhs.SubstType
&& lhs.UncurryLevel == rhs.UncurryLevel;
}
friend bool operator!=(const CachingTypeKey &lhs,
const CachingTypeKey &rhs) {
return !(lhs == rhs);
}
};
struct TypeKey {
/// An unsubstituted version of a type, dictating its abstraction patterns.
AbstractionPattern OrigType;
/// The substituted version of the type, dictating the types that
/// should be used in the lowered type.
CanType SubstType;
/// The uncurrying level of the type.
unsigned UncurryLevel;
CachingTypeKey getCachingKey() const {
assert(isCacheable());
return { (OrigType.hasGenericSignature()
? OrigType.getGenericSignature()
: nullptr),
OrigType.getCachingKey(),
SubstType,
UncurryLevel };
}
bool isCacheable() const {
return OrigType.hasCachingKey();
}
IsDependent_t isDependent() const {
if (SubstType->hasTypeParameter())
return IsDependent;
return IsNotDependent;
}
};
friend struct llvm::DenseMapInfo<CachingTypeKey>;
TypeKey getTypeKey(AbstractionPattern origTy, CanType substTy,
unsigned uncurryLevel) {
return {origTy, substTy, uncurryLevel};
}
struct OverrideKey {
SILDeclRef derived;
SILDeclRef base;
friend bool operator==(const OverrideKey &lhs,
const OverrideKey &rhs) {
return lhs.derived == rhs.derived
&& lhs.base == rhs.base;
}
friend bool operator!=(const OverrideKey &lhs,
const OverrideKey &rhs) {
return !(lhs == rhs);
}
};
friend struct llvm::DenseMapInfo<OverrideKey>;
/// Find a cached TypeLowering by TypeKey, or return null if one doesn't
/// exist.
const TypeLowering *find(TypeKey k);
/// Insert a mapping into the cache.
void insert(TypeKey k, const TypeLowering *tl);
/// Mapping for types independent on contextual generic parameters, which is
/// cleared when the generic context is popped.
llvm::DenseMap<CachingTypeKey, const TypeLowering *> IndependentTypes;
/// Mapping for types dependent on contextual generic parameters, which is
/// cleared when the generic context is popped.
llvm::DenseMap<CachingTypeKey, const TypeLowering *> DependentTypes;
llvm::DenseMap<SILDeclRef, SILConstantInfo> ConstantTypes;
llvm::DenseMap<OverrideKey, SILConstantInfo> ConstantOverrideTypes;
llvm::DenseMap<AnyFunctionRef, CaptureInfo> LoweredCaptures;
/// The current generic context signature.
CanGenericSignature CurGenericContext;
CanAnyFunctionType makeConstantInterfaceType(SILDeclRef constant);
/// Get the generic environment for a constant.
GenericEnvironment *getConstantGenericEnvironment(SILDeclRef constant);
// Types converted during foreign bridging.
#define BRIDGING_KNOWN_TYPE(BridgedModule,BridgedType) \
Optional<CanType> BridgedType##Ty;
#include "swift/SIL/BridgedTypes.def"
const TypeLowering &getTypeLoweringForLoweredType(TypeKey key);
const TypeLowering &getTypeLoweringForUncachedLoweredType(TypeKey key);
public:
SILModule &M;
ASTContext &Context;
TypeConverter(SILModule &m);
~TypeConverter();
TypeConverter(TypeConverter const &) = delete;
TypeConverter &operator=(TypeConverter const &) = delete;
/// Return the CaptureKind to use when capturing a decl.
CaptureKind getDeclCaptureKind(CapturedValue capture);
/// Return a most-general-possible abstraction pattern.
AbstractionPattern getMostGeneralAbstraction() {
return AbstractionPattern::getOpaque();
}
/// Get the calling convention used by witnesses of a protocol.
static SILFunctionTypeRepresentation
getProtocolWitnessRepresentation(ProtocolDecl *P) {
// ObjC protocols use the objc method convention.
if (P->isObjC())
return SILFunctionTypeRepresentation::ObjCMethod;
// Native protocols use the witness calling convention.
return SILFunctionTypeRepresentation::WitnessMethod;
}
/// Get the calling convention used to call a declaration.
SILFunctionTypeRepresentation getDeclRefRepresentation(SILDeclRef c);
/// Get the method dispatch strategy for a protocol.
static ProtocolDispatchStrategy getProtocolDispatchStrategy(ProtocolDecl *P);
/// True if a protocol uses witness tables for dynamic dispatch.
static bool protocolRequiresWitnessTable(ProtocolDecl *P) {
return ProtocolDescriptorFlags::needsWitnessTable
(getProtocolDispatchStrategy(P));
}
/// True if a type is passed indirectly at +0 when used as the "self"
/// parameter of its own methods.
///
/// TODO: We want this always to hold.
static bool isIndirectPlusZeroSelfParameter(Type T) {
// Calls through opaque protocols can be done with +0 rvalues. This allows
// us to avoid materializing copies of existentials.
return !T->hasReferenceSemantics()
&& (T->isExistentialType() || T->is<ArchetypeType>());
}
static bool isIndirectPlusZeroSelfParameter(SILType T) {
return isIndirectPlusZeroSelfParameter(T.getSwiftRValueType());
}
/// Lowers a Swift type to a SILType, and returns the SIL TypeLowering
/// for that type.
const TypeLowering &getTypeLowering(Type t, unsigned uncurryLevel = 0) {
AbstractionPattern pattern(CurGenericContext, t->getCanonicalType());
return getTypeLowering(pattern, t, uncurryLevel);
}
/// Lowers a Swift type to a SILType according to the abstraction
/// patterns of the given original type.
const TypeLowering &getTypeLowering(AbstractionPattern origType,
Type substType,
unsigned uncurryLevel = 0);
/// Returns the SIL TypeLowering for an already lowered SILType. If the
/// SILType is an address, returns the TypeLowering for the pointed-to
/// type.
const TypeLowering &getTypeLowering(SILType t);
// Returns the lowered SIL type for a Swift type.
SILType getLoweredType(Type t, unsigned uncurryLevel = 0) {
return getTypeLowering(t, uncurryLevel).getLoweredType();
}
// Returns the lowered SIL type for a Swift type.
SILType getLoweredType(AbstractionPattern origType, Type substType,
unsigned uncurryLevel = 0) {
return getTypeLowering(origType, substType, uncurryLevel).getLoweredType();
}
SILType getLoweredLoadableType(Type t, unsigned uncurryLevel = 0) {
const TypeLowering &ti = getTypeLowering(t, uncurryLevel);
assert(ti.isLoadable() && "unexpected address-only type");
return ti.getLoweredType();
}
AbstractionPattern getAbstractionPattern(AbstractStorageDecl *storage);
AbstractionPattern getAbstractionPattern(VarDecl *var);
AbstractionPattern getAbstractionPattern(SubscriptDecl *subscript);
AbstractionPattern getIndicesAbstractionPattern(SubscriptDecl *subscript);
AbstractionPattern getAbstractionPattern(EnumElementDecl *element);
SILType getLoweredTypeOfGlobal(VarDecl *var);
/// The return type of a materializeForSet contains a callback
/// whose type cannot be represented in the AST because it is
/// a polymorphic function value. This function returns the
/// unsubstituted lowered type of this callback.
CanSILFunctionType
getMaterializeForSetCallbackType(AbstractStorageDecl *storage,
CanGenericSignature genericSig,
Type selfType);
/// Return the SILFunctionType for a native function value of the
/// given type.
CanSILFunctionType getSILFunctionType(AbstractionPattern origType,
CanAnyFunctionType substType,
unsigned uncurryLevel);
/// Returns the formal type, lowered AST type, and SILFunctionType
/// for a constant reference.
SILConstantInfo getConstantInfo(SILDeclRef constant);
/// Returns the SIL type of a constant reference.
SILType getConstantType(SILDeclRef constant) {
return getConstantInfo(constant).getSILType();
}
/// Returns the SILFunctionType for the given declaration.
CanSILFunctionType getConstantFunctionType(SILDeclRef constant) {
return getConstantInfo(constant).SILFnType;
}
/// Returns the SILParameterInfo for the given declaration's `self` parameter.
/// `constant` must refer to a method.
SILParameterInfo getConstantSelfParameter(SILDeclRef constant);
/// Returns the SILFunctionType the given declaration must use to override.
/// Will be the same as getConstantFunctionType if the declaration does
/// not override.
CanSILFunctionType getConstantOverrideType(SILDeclRef constant) {
// Fast path if the constant isn't overridden.
if (constant.getNextOverriddenVTableEntry().isNull())
return getConstantFunctionType(constant);
SILDeclRef base = constant;
while (SILDeclRef overridden = base.getOverridden())
base = overridden;
return getConstantOverrideType(constant, base);
}
CanSILFunctionType getConstantOverrideType(SILDeclRef constant,
SILDeclRef base) {
return getConstantOverrideInfo(constant, base).SILFnType;
}
SILConstantInfo getConstantOverrideInfo(SILDeclRef constant,
SILDeclRef base);
/// Substitute the given function type so that it implements the
/// given substituted type.
CanSILFunctionType substFunctionType(CanSILFunctionType origFnType,
CanAnyFunctionType origLoweredType,
CanAnyFunctionType substLoweredInterfaceType,
const Optional<ForeignErrorConvention> &foreignError);
/// Get the empty tuple type as a SILType.
SILType getEmptyTupleType() {
return getLoweredType(TupleType::getEmpty(Context));
}
/// Get a function type curried with its capture context.
CanAnyFunctionType getFunctionInterfaceTypeWithCaptures(
CanAnyFunctionType funcType,
AnyFunctionRef closure);
/// Describes what we're trying to compute a bridged type for.
///
/// \see getLoweredBridgedType
enum BridgedTypePurpose {
ForArgument,
ForNonOptionalResult, // A result that should not be made more optional
ForResult,
ForMemory,
};
/// Map an AST-level type to the corresponding foreign representation type we
/// implicitly convert to for a given calling convention.
Type getLoweredBridgedType(AbstractionPattern pattern, Type t,
SILFunctionTypeRepresentation rep,
BridgedTypePurpose purpose);
/// Convert a nested function type into an uncurried AST representation.
CanAnyFunctionType getLoweredASTFunctionType(CanAnyFunctionType t,
unsigned uncurryLevel,
Optional<SILDeclRef> constant) {
return getLoweredASTFunctionType(t, uncurryLevel, t->getExtInfo(),
constant);
}
/// Convert a nested function type into an uncurried AST representation.
CanAnyFunctionType getLoweredASTFunctionType(CanAnyFunctionType t,
unsigned uncurryLevel,
AnyFunctionType::ExtInfo info,
Optional<SILDeclRef> constant);
/// Given a referenced value and the substituted formal type of a
/// resulting l-value expression, produce the substituted formal
/// type of the storage of the value.
///
/// \return - always an address type
SILType getSubstitutedStorageType(AbstractStorageDecl *value,
Type lvalueType);
/// Retrieve the set of archetypes closed over by the given function.
GenericEnvironment *getEffectiveGenericEnvironment(AnyFunctionRef fn,
CaptureInfo captureInfo);
/// Retrieve the set of generic parameters closed over by the given function.
CanGenericSignature getEffectiveGenericSignature(AnyFunctionRef fn,
CaptureInfo captureInfo);
/// Push a generic function context. See GenericContextScope for an RAII
/// interface to this function.
///
/// Types containing generic parameter references must be lowered in a generic
/// context. There can be at most one level of generic context active at any
/// point in time.
void pushGenericContext(CanGenericSignature sig);
/// Return the current generic context. This should only be used in
/// the type-conversion routines.
CanGenericSignature getCurGenericContext() const {
return CurGenericContext;
}
/// Pop a generic function context. See GenericContextScope for an RAII
/// interface to this function. There must be an active generic context.
void popGenericContext(CanGenericSignature sig);
/// Known types for bridging.
#define BRIDGING_KNOWN_TYPE(BridgedModule,BridgedType) \
CanType get##BridgedType##Type();
#include "swift/SIL/BridgedTypes.def"
/// Get the capture list from a closure, with transitive function captures
/// flattened.
CaptureInfo getLoweredLocalCaptures(AnyFunctionRef fn);
enum class ABIDifference : uint8_t {
// No ABI differences, function can be trivially bitcast to result type.
Trivial,
// Representation difference requires thin-to-thick conversion.
ThinToThick,
// Non-trivial difference requires thunk.
NeedsThunk
};
/// \brief Test if type1 is ABI compatible with type2, and can be converted
/// with a trivial bitcast.
///
/// Note that type1 and type2 must be lowered types, and type1 must be a
/// subtype of type2.
///
/// The ABI compatible relation is not symmetric on function types -- while
/// T and T! are both subtypes of each other, a calling convention conversion
/// of T! to T always requires a thunk.
ABIDifference checkForABIDifferences(SILType type1, SILType type2);
/// \brief Same as above but for SIL function types.
ABIDifference checkFunctionForABIDifferences(SILFunctionType *fnTy1,
SILFunctionType *fnTy2);
/// Lower the function type as a possible substitution for the type of
/// \p constant. The result is not cached as part of the constant's normal
/// ConstantInfo.
CanSILFunctionType
getUncachedSILFunctionTypeForConstant(SILDeclRef constant,
CanAnyFunctionType origInterfaceType);
private:
CanType getLoweredRValueType(AbstractionPattern origType, CanType substType,
unsigned uncurryLevel);
Type getLoweredCBridgedType(AbstractionPattern pattern, Type t,
bool canBridgeBool,
bool bridgedCollectionsAreOptional);
CanType getBridgedInputType(SILFunctionTypeRepresentation rep,
AbstractionPattern pattern,
CanType input);
CanType getBridgedResultType(SILFunctionTypeRepresentation rep,
AbstractionPattern pattern,
CanType result,
bool suppressOptional);
CanAnyFunctionType getBridgedFunctionType(AbstractionPattern fnPattern,
CanAnyFunctionType fnType,
AnyFunctionType::ExtInfo extInfo);
};
inline const TypeLowering &
TypeLowering::getSemanticTypeLowering(TypeConverter &TC) const {
// If you change this, change getSemanticType() too.
auto storageType = getLoweredType().getSwiftRValueType();
if (auto refType = dyn_cast<ReferenceStorageType>(storageType))
return TC.getTypeLowering(refType.getReferentType());
return *this;
}
/// RAII interface to push a generic context.
class GenericContextScope {
TypeConverter &TC;
CanGenericSignature Sig;
public:
GenericContextScope(TypeConverter &TC, CanGenericSignature sig)
: TC(TC), Sig(sig)
{
TC.pushGenericContext(sig);
}
~GenericContextScope() {
TC.popGenericContext(Sig);
}
private:
GenericContextScope(const GenericContextScope&) = delete;
GenericContextScope &operator=(const GenericContextScope&) = delete;
};
} // namespace Lowering
} // namespace swift
namespace llvm {
template<> struct DenseMapInfo<swift::Lowering::TypeConverter::CachingTypeKey> {
typedef swift::Lowering::TypeConverter::CachingTypeKey CachingTypeKey;
using APCachingKey = swift::Lowering::AbstractionPattern::CachingKey;
using CachingKeyInfo = DenseMapInfo<APCachingKey>;
using CanTypeInfo = DenseMapInfo<swift::CanType>;
// Use the second field because the first field can validly be null.
static CachingTypeKey getEmptyKey() {
return {nullptr, APCachingKey(), CanTypeInfo::getEmptyKey(), 0};
}
static CachingTypeKey getTombstoneKey() {
return {nullptr, APCachingKey(), CanTypeInfo::getTombstoneKey(), 0};
}
static unsigned getHashValue(CachingTypeKey val) {
auto hashSig =
DenseMapInfo<swift::GenericSignature *>::getHashValue(val.Sig);
auto hashOrig =
CachingKeyInfo::getHashValue(val.OrigType);
auto hashSubst =
DenseMapInfo<swift::CanType>::getHashValue(val.SubstType);
return hash_combine(hashSig, hashOrig, hashSubst, val.UncurryLevel);
}
static bool isEqual(CachingTypeKey LHS, CachingTypeKey RHS) {
return LHS == RHS;
}
};
template<> struct DenseMapInfo<swift::Lowering::TypeConverter::OverrideKey> {
typedef swift::Lowering::TypeConverter::OverrideKey OverrideKey;
using SILDeclRefInfo = DenseMapInfo<swift::SILDeclRef>;
static OverrideKey getEmptyKey() {
return {SILDeclRefInfo::getEmptyKey(), SILDeclRefInfo::getEmptyKey()};
}
static OverrideKey getTombstoneKey() {
return {SILDeclRefInfo::getTombstoneKey(), SILDeclRefInfo::getTombstoneKey()};
}
static unsigned getHashValue(OverrideKey val) {
return hash_combine(SILDeclRefInfo::getHashValue(val.base),
SILDeclRefInfo::getHashValue(val.derived));
}
static bool isEqual(OverrideKey LHS, OverrideKey RHS) {
return LHS == RHS;
}
};
}
#endif