blob: 93df4f66affa4ecf749525eda25f57849dafb5d5 [file] [log] [blame]
//===--- AbstractionPattern.h - SIL type abstraction patterns ---*- 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 AbstractionPattern class, which is used to
// lower formal AST types into their SIL lowerings.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_SIL_ABSTRACTIONPATTERN_H
#define SWIFT_SIL_ABSTRACTIONPATTERN_H
#include "swift/AST/Decl.h"
#include "swift/AST/Types.h"
namespace llvm {
template <class T> class function_ref;
}
namespace clang {
class CXXMethodDecl;
class ObjCMethodDecl;
class Type;
class ValueDecl;
}
namespace swift {
namespace Lowering {
/// A pattern for the abstraction of a value.
///
/// The representation of values in Swift can vary according to how
/// their type is abstracted: which is to say, according to the pattern
/// of opaque type variables within their type. The main motivation
/// here is performance: it would be far easier for types to adopt a
/// single representation regardless of their abstraction, but this
/// would force Swift to adopt a very inefficient representation for
/// abstractable values.
///
/// For example, consider the comparison function on Int:
/// func <(lhs : Int, rhs : Int) -> Bool
///
/// This function can be used as an opaque value of type
/// (Int,Int)->Bool. An optimal representation of values of that type
/// (ignoring context parameters for the moment) would be a pointer to
/// a function that takes these two arguments directly in registers and
/// returns the result directly in a register.
///
/// (It's important to remember throughout this discussion that we're
/// talking about abstract values. There's absolutely nothing that
/// requires direct uses of the function to follow the same conventions
/// as abstract uses! A direct use of a declaration --- even one that
/// implies an indirect call, like a class's instance method ---
/// provides a concrete specification for exactly how to interact with
/// value.)
///
/// However, that representation is problematic in the presence of
/// generics. This function could be passed off to any of the following
/// generic functions:
/// func foo<T>(f : (T, Int) -> Bool)
/// func bar<U,V>(f : (U, V) -> Bool)
/// func baz<W>(f : (Int, Int) -> W)
///
/// These generic functions all need to be able to call 'f'. But in
/// Swift's implementation model, these functions don't have to be
/// instantiated for different parameter types, which means that (e.g.)
/// the same 'baz' implementation needs to also be able to work when
/// W=String. But the optimal way to pass an Int to a function might
/// well be different from the optimal way to pass a String.
///
/// And this runs in both directions: a generic function might return
/// a function that the caller would like to use as an (Int,Int)->Bool:
/// func getFalseFunction<T>() -> (T,T)->Bool
///
/// There are three ways we can deal with this:
///
/// 1. Give all types in Swift a common representation. The generic
/// implementation can work with both W=String and W=Int because
/// both of those types have the same (direct) storage representation.
/// That's pretty clearly not an acceptable sacrifice.
///
/// 2. Adopt a most-general representation of function types that is
/// used for opaque values; for example, all parameters and results
/// could be passed indirectly. Concrete values must be coerced to
/// this representation when made abstract. Unfortunately, there
/// are a lot of obvious situations where this is sub-optimal:
/// for example, in totally non-generic code that just passes around
/// a value of type (Int,Int)->Bool.
///
/// 3. Permit the representation of values to vary by abstraction.
/// Values require coercion when changing abstraction patterns.
/// For example, the argument to 'bar' would be expected to return
/// its Bool result directly but take the T and U parameters indirectly.
/// When '<' is passed to this, what must actually be passed is a
/// thunk that loads both indirect parameters before calling '<'.
///
/// There is one major risk with (3): naively implemented, a single
/// function value which undergoes many coercions could build up a
/// linear number of re-abstraction thunks. However, this can be
/// solved dynamically by applying thunks with a runtime function that
/// can recognize and bypass its own previous handiwork.
///
/// In general, abstraction patterns are derived from some explicit
/// type expression, such as the written type of a variable or
/// parameter. This works whenever the expression directly provides
/// structure for the type in question; for example, when the original
/// type is (T,Int)->Bool and we are working with an (Int,Int)->Bool
/// substitution. However, it is inadequate when the expression does
/// not provide structure at the appropriate level, i.e. when that
/// level is substituted in: when the original type is merely T. In
/// these cases, we must devolve to a representation which all legal
/// substitutors will agree upon.
///
/// The most general type of a function type replaces all parameters and the
/// result with fresh, unrestricted generic parameters.
///
/// That is, if we have a substituted function type:
///
/// (UnicodeScalar, (Int, Float), Double) -> (Bool, String)
///
/// then its most general form is
///
/// (A, B, C) -> D
///
/// because there is a valid substitution
/// A := UnicodeScalar
/// B := (Int, Float)
/// C := Double
/// D := (Bool, String)
///
class AbstractionPattern {
enum class Kind {
/// A type reference. OrigType is valid.
Type,
/// An invalid pattern.
Invalid,
/// A completely opaque abstraction pattern.
Opaque,
/// An open-coded tuple pattern. OrigTupleElements is valid.
/// OtherData is the number of tuple elements.
Tuple,
/// A discarded value. OrigType is valid.
Discard,
/// A type reference with a Clang type. OrigType and ClangType are valid.
ClangType,
/// The curried imported type of an Objective-C method (that is,
/// 'Self -> Input -> Result'). OrigType is valid and is a function
/// type. ObjCMethod is valid. OtherData is an encoded foreign
/// error index.
CurriedObjCMethodType,
/// The partially-applied curried imported type of an Objective-C
/// method (that is, 'Input -> Result'). OrigType is valid and is a
/// function type. ObjCMethod is valid. OtherData is an encoded
/// foreign error index.
PartialCurriedObjCMethodType,
/// The uncurried imported type of a C function imported as a method.
/// OrigType is valid and is a function type. ClangType is valid and is
/// a function type. OtherData is an encoded ImportAsMemberStatus.
CFunctionAsMethodType,
/// The curried imported type of a C function imported as a method.
/// OrigType is valid and is a function type. ClangType is valid and is
/// a function type. OtherData is an encoded ImportAsMemberStatus.
CurriedCFunctionAsMethodType,
/// The partially-applied curried imported type of a C function imported as
/// a method.
/// OrigType is valid and is a function type. ClangType is valid and is
/// a function type. OtherData is an encoded ImportAsMemberStatus.
PartialCurriedCFunctionAsMethodType,
/// The uncurried imported type of an Objective-C method (that is,
/// '(Input, Self) -> Result'). OrigType is valid and is a function
/// type. ObjCMethod is valid. OtherData is an encoded foreign
/// error index.
ObjCMethodType,
/// The type of an ObjC block used as a completion handler for
/// an API that has been imported into Swift as async,
/// representing the tuple of results of the async projection of the
/// API.
ObjCCompletionHandlerArgumentsType,
/// The uncurried imported type of a C++ non-operator non-static member
/// function. OrigType is valid and is a function type. CXXMethod is valid.
CXXMethodType,
/// The curried imported type of a C++ non-operator non-static member
/// function. OrigType is valid and is a function type. CXXMethod is valid.
CurriedCXXMethodType,
/// The partially-applied curried imported type of a C++ non-operator
/// non-static member function. OrigType is valid and is a function type.
/// CXXMethod is valid.
PartialCurriedCXXMethodType,
/// The uncurried imported type of a C++ operator non-static member
/// function. OrigType is valid and is a function type. CXXMethod is valid.
CXXOperatorMethodType,
/// The curried imported type of a C++ operator non-static member function.
/// OrigType is valid and is a function type. CXXMethod is valid.
CurriedCXXOperatorMethodType,
/// The partially-applied curried imported type of a C++ operator non-static
/// member function. OrigType is valid and is a function type. CXXMethod is
/// valid.
PartialCurriedCXXOperatorMethodType,
/// A Swift function whose parameters and results are opaque. This is
/// like `AP::Type<T>((T) -> T)`, except that the number of parameters is
/// unspecified.
///
/// This is used to construct the abstraction pattern for the
/// derivative function of a function with opaque abstraction pattern. See
/// `OpaqueDerivativeFunction`.
OpaqueFunction,
/// A Swift function whose parameters are opaque and whose result is the
/// tuple abstraction pattern `(AP::Opaque, AP::OpaqueFunction)`.
///
/// Purpose: when we reabstract `@differentiable` function-typed values
/// using the`AP::Opaque` pattern, we use `AP::Opaque` to reabstract the
/// original function in the bundle and `AP::OpaqueDerivativeFunction` to
/// reabstract the derivative functions in the bundle. This preserves the
/// `@differentiable` function invariant that the derivative type
/// (`SILFunctionType::getAutoDiffDerivativeFunctionType()`) of the original
/// function is equal to the type of the derivative function. For example:
///
/// differentiable_function
/// [parameters 0]
/// %0 : $@callee_guaranteed (Float) -> Float
/// with_derivative {
/// %1 : $@callee_guaranteed (Float) -> (
/// Float,
/// @owned @callee_guaranteed (Float) -> Float
/// ),
/// %2 : $@callee_guaranteed (Float) -> (
/// Float,
/// @owned @callee_guaranteed (Float) -> Float
/// )
/// }
///
/// The invariant-respecting abstraction of this value to `AP::Opaque` is:
///
/// differentiable_function
/// [parameters 0]
/// %3 : $@callee_guaranteed (@in_guaranteed Float) -> @out Float
/// with_derivative {
/// %4 : $@callee_guaranteed (@in_guaranteed Float) -> (
/// @out Float,
/// @owned @callee_guaranteed (@in_guaranteed Float) -> @out Float
/// ),
/// %5 : $@callee_guaranteed (@in_guaranteed Float) -> (
/// @out Float,
/// @owned @callee_guaranteed (@in_guaranteed Float) -> @out Float
/// )
/// }
///
/// In particular:
///
/// - The reabstraction %0 => %3 uses pattern `AP::Opaque`.
/// - The reabstraction %1 => %4 uses pattern
/// `AP::OpaqueDerivativeFunction`, which maximally abstracts all the
/// parameters, and abstracts the result as the tuple
/// `(AP::Opaque, AP::OpaqueFunction)`.
/// - The reabstraction %2 => %5 similarly uses pattern
/// `AP::OpaqueDerivativeFunction`.
OpaqueDerivativeFunction,
};
class EncodedForeignInfo {
unsigned Value;
enum Error_t {
Error,
};
enum Async_t {
Async,
};
public:
enum ForeignKind {
IsNotForeign,
IsError,
IsAsync,
};
private:
friend AbstractionPattern;
EncodedForeignInfo() : Value(0) {}
EncodedForeignInfo(Error_t,
unsigned errorParameterIndex,
bool replaceParamWithVoid,
bool stripsResultOptionality)
: Value(1
+ (unsigned(IsError) - 1)
+ (unsigned(stripsResultOptionality) << 1)
+ (unsigned(replaceParamWithVoid) << 2)
+ (errorParameterIndex << 3)) {
assert(getKind() == IsError);
assert(getErrorParamIndex() == errorParameterIndex);
assert(hasErrorParameterReplacedWithVoid() == replaceParamWithVoid);
assert(errorStripsResultOptionality() == stripsResultOptionality);
}
EncodedForeignInfo(Async_t,
unsigned completionParameterIndex,
Optional<unsigned> completionErrorParameterIndex)
: Value(1
+ (unsigned(IsAsync) - 1)
+ (unsigned(completionParameterIndex) << 1)
+ ((completionErrorParameterIndex ? *completionErrorParameterIndex + 1
: 0) << 21)) {
assert(getKind() == IsAsync);
assert(getAsyncCompletionHandlerParamIndex() == completionParameterIndex);
assert(getAsyncCompletionHandlerErrorParamIndex() == completionErrorParameterIndex);
}
public:
static EncodedForeignInfo
encode(const Optional<ForeignErrorConvention> &foreignError,
const Optional<ForeignAsyncConvention> &foreignAsync);
bool hasValue() const { return Value != 0; }
ForeignKind getKind() const {
if (!hasValue())
return IsNotForeign;
return ForeignKind((Value - 1 & 1) + 1);
}
bool errorStripsResultOptionality() const {
if (getKind() != IsError) return false;
return (Value - 1) & 2;
}
bool hasErrorParameterReplacedWithVoid() const {
if (getKind() != IsError) return false;
return (Value - 1) & 4;
}
unsigned getErrorParamIndex() const {
assert(getKind() == IsError);
return (Value - 1) >> 3;
}
unsigned getAsyncCompletionHandlerParamIndex() const {
assert(getKind() == IsAsync);
return ((Value - 1) >> 1) & 0xFFFFFu;
}
Optional<unsigned> getAsyncCompletionHandlerErrorParamIndex() const {
assert(getKind() == IsAsync);
unsigned encodedValue = (Value - 1) >> 21;
if (encodedValue == 0) {
return llvm::None;
}
return encodedValue - 1;
}
unsigned getForeignParamIndex() const {
switch (getKind()) {
case IsNotForeign:
llvm_unreachable("no foreign param");
case IsError:
return getErrorParamIndex();
case IsAsync:
return getAsyncCompletionHandlerParamIndex();
}
llvm_unreachable("uncovered switch");
}
unsigned getOpaqueValue() const { return Value; }
static EncodedForeignInfo fromOpaqueValue(unsigned value) {
EncodedForeignInfo result;
result.Value = value;
return result;
}
};
static constexpr const unsigned NumOtherDataBits = 28;
static constexpr const unsigned MaxOtherData = (1 << NumOtherDataBits) - 1;
unsigned TheKind : 33 - NumOtherDataBits;
unsigned OtherData : NumOtherDataBits;
CanType OrigType;
union {
const clang::Type *ClangType;
const clang::ObjCMethodDecl *ObjCMethod;
const clang::CXXMethodDecl *CXXMethod;
const AbstractionPattern *OrigTupleElements;
};
CanGenericSignature GenericSig;
Kind getKind() const { return Kind(TheKind); }
CanGenericSignature getGenericSignatureForFunctionComponent() const {
if (auto genericFn = dyn_cast<GenericFunctionType>(getType())) {
return genericFn.getGenericSignature();
} else {
return getGenericSignature();
}
}
unsigned getNumTupleElements_Stored() const {
assert(getKind() == Kind::Tuple);
return OtherData;
}
bool hasStoredClangType() const {
switch (getKind()) {
case Kind::ClangType:
case Kind::CFunctionAsMethodType:
case Kind::CurriedCFunctionAsMethodType:
case Kind::PartialCurriedCFunctionAsMethodType:
case Kind::ObjCCompletionHandlerArgumentsType:
return true;
default:
return false;
}
}
bool hasStoredCXXMethod() const {
switch (getKind()) {
case Kind::CXXMethodType:
case Kind::CurriedCXXMethodType:
case Kind::PartialCurriedCXXMethodType:
case Kind::CXXOperatorMethodType:
case Kind::CurriedCXXOperatorMethodType:
case Kind::PartialCurriedCXXOperatorMethodType:
return true;
default:
return false;
}
}
bool hasStoredObjCMethod() const {
switch (getKind()) {
case Kind::CurriedObjCMethodType:
case Kind::PartialCurriedObjCMethodType:
case Kind::ObjCMethodType:
return true;
default:
return false;
}
}
bool hasStoredForeignInfo() const {
switch (getKind()) {
case Kind::CurriedObjCMethodType:
case Kind::PartialCurriedObjCMethodType:
case Kind::ObjCMethodType:
case Kind::ObjCCompletionHandlerArgumentsType:
return true;
default:
return false;
}
}
bool hasImportAsMemberStatus() const {
switch (getKind()) {
case Kind::CFunctionAsMethodType:
case Kind::CurriedCFunctionAsMethodType:
case Kind::PartialCurriedCFunctionAsMethodType:
return true;
default:
return false;
}
}
void initSwiftType(CanGenericSignature signature, CanType origType,
Kind kind = Kind::Type) {
assert(signature || !origType->hasTypeParameter());
TheKind = unsigned(kind);
OrigType = origType;
GenericSig = CanGenericSignature();
if (OrigType->hasTypeParameter()) {
assert(OrigType == signature->getCanonicalTypeInContext(origType));
GenericSig = signature;
}
}
void initClangType(CanGenericSignature signature,
CanType origType, const clang::Type *clangType,
Kind kind = Kind::ClangType) {
initSwiftType(signature, origType, kind);
ClangType = clangType;
}
void initObjCMethod(CanGenericSignature signature,
CanType origType, const clang::ObjCMethodDecl *method,
Kind kind, EncodedForeignInfo errorInfo) {
initSwiftType(signature, origType, kind);
ObjCMethod = method;
OtherData = errorInfo.getOpaqueValue();
}
void initCFunctionAsMethod(CanGenericSignature signature,
CanType origType, const clang::Type *clangType,
Kind kind,
ImportAsMemberStatus memberStatus) {
initClangType(signature, origType, clangType, kind);
OtherData = memberStatus.getRawValue();
}
void initCXXMethod(CanGenericSignature signature, CanType origType,
const clang::CXXMethodDecl *method, Kind kind) {
initSwiftType(signature, origType, kind);
CXXMethod = method;
}
AbstractionPattern() {}
explicit AbstractionPattern(Kind kind) : TheKind(unsigned(kind)) {}
public:
explicit AbstractionPattern(Type origType)
: AbstractionPattern(origType->getCanonicalType()) {}
explicit AbstractionPattern(CanType origType)
: AbstractionPattern(nullptr, origType) {}
explicit AbstractionPattern(CanGenericSignature signature, CanType origType) {
initSwiftType(signature, origType);
}
explicit AbstractionPattern(CanType origType, const clang::Type *clangType)
: AbstractionPattern(nullptr, origType, clangType) {}
explicit AbstractionPattern(CanGenericSignature signature, CanType origType,
const clang::Type *clangType) {
initClangType(signature, origType, clangType);
}
static AbstractionPattern getOpaque() {
return AbstractionPattern(Kind::Opaque);
}
static AbstractionPattern getInvalid() {
return AbstractionPattern(Kind::Invalid);
}
static AbstractionPattern getOpaqueFunction() {
return AbstractionPattern(Kind::OpaqueFunction);
}
static AbstractionPattern getOpaqueDerivativeFunction() {
return AbstractionPattern(Kind::OpaqueDerivativeFunction);
}
bool hasGenericSignature() const {
switch (getKind()) {
case Kind::Type:
case Kind::Discard:
case Kind::ClangType:
case Kind::CFunctionAsMethodType:
case Kind::CurriedCFunctionAsMethodType:
case Kind::PartialCurriedCFunctionAsMethodType:
case Kind::CurriedObjCMethodType:
case Kind::PartialCurriedObjCMethodType:
case Kind::ObjCMethodType:
case Kind::CXXMethodType:
case Kind::CurriedCXXMethodType:
case Kind::PartialCurriedCXXMethodType:
case Kind::CXXOperatorMethodType:
case Kind::CurriedCXXOperatorMethodType:
case Kind::PartialCurriedCXXOperatorMethodType:
case Kind::ObjCCompletionHandlerArgumentsType:
return true;
case Kind::Invalid:
case Kind::Opaque:
case Kind::Tuple:
case Kind::OpaqueFunction:
case Kind::OpaqueDerivativeFunction:
return false;
}
llvm_unreachable("Unhandled AbstractionPatternKind in switch");
}
CanGenericSignature getGenericSignature() const {
assert(hasGenericSignature());
return CanGenericSignature(GenericSig);
}
CanGenericSignature getGenericSignatureOrNull() const {
if (!hasGenericSignature())
return CanGenericSignature();
return CanGenericSignature(GenericSig);
}
/// Return an open-coded abstraction pattern for a tuple. The
/// caller is responsible for ensuring that the storage for the
/// tuple elements is valid for as long as the abstraction pattern is.
static AbstractionPattern getTuple(ArrayRef<AbstractionPattern> tuple) {
AbstractionPattern pattern(Kind::Tuple);
pattern.OtherData = tuple.size();
pattern.OrigTupleElements = tuple.data();
return pattern;
}
/// Return an abstraction pattern for a result tuple
/// corresponding to the parameters of a completion handler
/// block of an API that was imported as async.
static AbstractionPattern
getObjCCompletionHandlerArgumentsType(CanGenericSignature sig,
CanType origTupleType,
const clang::Type *clangBlockType,
EncodedForeignInfo foreignInfo) {
AbstractionPattern pattern(Kind::ObjCCompletionHandlerArgumentsType);
pattern.initClangType(sig, origTupleType, clangBlockType,
Kind::ObjCCompletionHandlerArgumentsType);
pattern.OtherData = foreignInfo.getOpaqueValue();
return pattern;
}
public:
/// Return an abstraction pattern for the curried type of an
/// Objective-C method.
static AbstractionPattern
getCurriedObjCMethod(CanType origType, const clang::ObjCMethodDecl *method,
const Optional<ForeignErrorConvention> &foreignError,
const Optional<ForeignAsyncConvention> &foreignAsync);
/// Return an abstraction pattern for the uncurried type of a C function
/// imported as a method.
///
/// For example, if the original function is:
/// void CCRefrigatorSetTemperature(CCRefrigeratorRef fridge,
/// CCRefrigeratorCompartment compartment,
/// CCTemperature temperature);
/// then the uncurried type is:
/// ((CCRefrigeratorComponent, CCTemperature), CCRefrigerator) -> ()
static AbstractionPattern
getCFunctionAsMethod(CanType origType, const clang::Type *clangType,
ImportAsMemberStatus memberStatus) {
assert(isa<AnyFunctionType>(origType));
AbstractionPattern pattern;
pattern.initCFunctionAsMethod(nullptr, origType, clangType,
Kind::CFunctionAsMethodType,
memberStatus);
return pattern;
}
/// Return an abstraction pattern for the curried type of a
/// C function imported as a method.
///
/// For example, if the original function is:
/// void CCRefrigatorSetTemperature(CCRefrigeratorRef fridge,
/// CCRefrigeratorCompartment compartment,
/// CCTemperature temperature);
/// then the curried type is:
/// (CCRefrigerator) -> (CCRefrigeratorCompartment, CCTemperature) -> ()
static AbstractionPattern
getCurriedCFunctionAsMethod(CanType origType,
const AbstractFunctionDecl *function);
/// Return an abstraction pattern for the curried type of a C++ method.
static AbstractionPattern
getCurriedCXXMethod(CanType origType, const AbstractFunctionDecl *function);
static AbstractionPattern
getCurriedCXXOperatorMethod(CanType origType,
const AbstractFunctionDecl *function);
/// Return an abstraction pattern for the uncurried type of a C++ method.
///
/// For example, if the original function is:
/// void Refrigerator::SetTemperature(RefrigeratorCompartment compartment,
/// Temperature temperature);
/// then the uncurried type is:
/// ((RefrigeratorCompartment, Temperature), Refrigerator) -> ()
static AbstractionPattern getCXXMethod(CanType origType,
const clang::CXXMethodDecl *method) {
assert(isa<AnyFunctionType>(origType));
AbstractionPattern pattern;
pattern.initCXXMethod(nullptr, origType, method, Kind::CXXMethodType);
return pattern;
}
static AbstractionPattern
getCXXOperatorMethod(CanType origType, const clang::CXXMethodDecl *method) {
assert(isa<AnyFunctionType>(origType));
AbstractionPattern pattern;
pattern.initCXXMethod(nullptr, origType, method,
Kind::CXXOperatorMethodType);
return pattern;
}
/// Return an abstraction pattern for the curried type of a C++ method.
///
/// For example, if the original function is:
/// void Refrigerator::SetTemperature(RefrigeratorCompartment compartment,
/// Temperature temperature);
/// then the curried type:
/// (Refrigerator) -> (Compartment, Temperature) -> ()
static AbstractionPattern
getCurriedCXXMethod(CanType origType, const clang::CXXMethodDecl *method) {
assert(isa<AnyFunctionType>(origType));
AbstractionPattern pattern;
pattern.initCXXMethod(nullptr, origType, method,
Kind::CurriedCXXMethodType);
return pattern;
}
static AbstractionPattern
getCurriedCXXOperatorMethod(CanType origType,
const clang::CXXMethodDecl *method) {
assert(isa<AnyFunctionType>(origType));
AbstractionPattern pattern;
pattern.initCXXMethod(nullptr, origType, method,
Kind::CurriedCXXOperatorMethodType);
return pattern;
}
/// For a C-function-as-method pattern,
/// get the index of the C function parameter that was imported as the
/// `self` parameter of the imported method, or None if this is a static
/// method with no `self` parameter.
ImportAsMemberStatus getImportAsMemberStatus() const {
assert(hasImportAsMemberStatus());
return ImportAsMemberStatus(OtherData);
}
/// Return an abstraction pattern for a value that is discarded after being
/// evaluated.
static AbstractionPattern
getDiscard(CanGenericSignature signature, CanType origType) {
AbstractionPattern pattern;
pattern.initSwiftType(signature, origType, Kind::Discard);
return pattern;
}
/// Return an abstraction pattern for the type of the given struct field or enum case
/// substituted in `this` type.
///
/// Note that, for most purposes, you should lower a field's type against its
/// *unsubstituted* interface type.
AbstractionPattern
unsafeGetSubstFieldType(ValueDecl *member,
CanType origMemberType = CanType()) const;
private:
/// Return an abstraction pattern for the curried type of an
/// Objective-C method.
static AbstractionPattern
getCurriedObjCMethod(CanType origType, const clang::ObjCMethodDecl *method,
EncodedForeignInfo errorInfo) {
assert(isa<AnyFunctionType>(origType));
AbstractionPattern pattern;
pattern.initObjCMethod(nullptr, origType, method,
Kind::CurriedObjCMethodType, errorInfo);
return pattern;
}
static AbstractionPattern
getCurriedCFunctionAsMethod(CanType origType,
const clang::Type *clangType,
ImportAsMemberStatus memberStatus) {
assert(isa<AnyFunctionType>(origType));
AbstractionPattern pattern;
pattern.initCFunctionAsMethod(nullptr, origType, clangType,
Kind::CurriedCFunctionAsMethodType,
memberStatus);
return pattern;
}
/// Return an abstraction pattern for the partially-applied curried
/// type of an Objective-C method.
static AbstractionPattern
getPartialCurriedObjCMethod(CanGenericSignature signature,
CanType origType,
const clang::ObjCMethodDecl *method,
EncodedForeignInfo errorInfo) {
assert(isa<AnyFunctionType>(origType));
AbstractionPattern pattern;
pattern.initObjCMethod(signature, origType, method,
Kind::PartialCurriedObjCMethodType, errorInfo);
return pattern;
}
/// Return an abstraction pattern for the partially-applied curried
/// type of a C function imported as a method.
///
/// For example, if the original function is:
/// CCRefrigatorSetTemperature(CCRefrigeratorRef, CCTemperature)
/// then the curried type is:
/// (CCRefrigerator) -> (CCTemperature) -> ()
/// and the partially-applied curried type is:
/// (CCTemperature) -> ()
static AbstractionPattern
getPartialCurriedCFunctionAsMethod(CanGenericSignature signature,
CanType origType,
const clang::Type *clangType,
ImportAsMemberStatus memberStatus) {
assert(isa<AnyFunctionType>(origType));
AbstractionPattern pattern;
pattern.initCFunctionAsMethod(signature, origType, clangType,
Kind::PartialCurriedCFunctionAsMethodType,
memberStatus);
return pattern;
}
/// Return an abstraction pattern for the partially-applied curried
/// type of an C++ method.
///
/// For example, if the original function is:
/// void Refrigerator::SetTemperature(RefrigeratorCompartment compartment,
/// Temperature temperature);
/// then the partially-applied curried type is:
/// (Compartment, Temperature) -> ()
static AbstractionPattern
getPartialCurriedCXXMethod(CanGenericSignature signature, CanType origType,
const clang::CXXMethodDecl *method) {
assert(isa<AnyFunctionType>(origType));
AbstractionPattern pattern;
pattern.initCXXMethod(signature, origType, method,
Kind::PartialCurriedCXXMethodType);
return pattern;
}
static AbstractionPattern
getPartialCurriedCXXOperatorMethod(CanGenericSignature signature,
CanType origType,
const clang::CXXMethodDecl *method) {
assert(isa<AnyFunctionType>(origType));
AbstractionPattern pattern;
pattern.initCXXMethod(signature, origType, method,
Kind::PartialCurriedCXXOperatorMethodType);
return pattern;
}
public:
/// Return an abstraction pattern for the type of an Objective-C method.
static AbstractionPattern
getObjCMethod(CanType origType, const clang::ObjCMethodDecl *method,
const Optional<ForeignErrorConvention> &foreignError,
const Optional<ForeignAsyncConvention> &foreignAsync);
private:
/// Return an abstraction pattern for the uncurried type of an
/// Objective-C method.
static AbstractionPattern
getObjCMethod(CanType origType, const clang::ObjCMethodDecl *method,
EncodedForeignInfo errorInfo) {
assert(isa<AnyFunctionType>(origType));
AbstractionPattern pattern;
pattern.initObjCMethod(nullptr, origType, method, Kind::ObjCMethodType,
errorInfo);
return pattern;
}
/// Return a pattern corresponding to the 'self' parameter of the
/// current Objective-C method.
AbstractionPattern getObjCMethodSelfPattern(CanType paramType) const;
/// Return a pattern corresponding to the 'self' parameter of the
/// current C function imported as a method.
AbstractionPattern getCFunctionAsMethodSelfPattern(CanType paramType) const;
/// Return a pattern corresponding to the 'self' parameter of the
/// current C++ method.
AbstractionPattern getCXXMethodSelfPattern(CanType paramType) const;
public:
/// Return an abstraction pattern with an added level of optionality.
///
/// The based abstraction pattern must be either opaque or based on
/// a Clang or Swift type. That is, it cannot be a tuple or an ObjC
/// method type.
static AbstractionPattern getOptional(AbstractionPattern objectPattern);
/// Does this abstraction pattern have something that can be used as a key?
bool hasCachingKey() const {
// Only the simplest Kind::Type pattern has a caching key; we
// don't want to try to unique by Clang node.
return getKind() == Kind::Type || getKind() == Kind::Opaque
|| getKind() == Kind::Discard;
}
using CachingKey = CanType;
CachingKey getCachingKey() const {
assert(hasCachingKey());
return OrigType;
}
bool isValid() const {
return getKind() != Kind::Invalid;
}
bool isTypeParameterOrOpaqueArchetype() const {
switch (getKind()) {
case Kind::Opaque:
return true;
case Kind::Type:
case Kind::ClangType:
case Kind::Discard: {
auto type = getType();
if (isa<DependentMemberType>(type) ||
isa<GenericTypeParamType>(type)) {
return true;
}
if (isa<ArchetypeType>(type)) {
return true;
}
return false;
}
default:
return false;
}
}
bool isTypeParameter() const {
switch (getKind()) {
case Kind::Opaque:
return true;
case Kind::Type:
case Kind::ClangType:
case Kind::Discard: {
auto type = getType();
if (isa<DependentMemberType>(type) ||
isa<GenericTypeParamType>(type)) {
return true;
}
if (auto archetype = dyn_cast<ArchetypeType>(type)) {
return !isa<OpaqueTypeArchetypeType>(archetype->getRoot());
}
return false;
}
default:
return false;
}
}
/// Is this an interface type that is subject to a concrete
/// same-type constraint?
bool isConcreteType() const;
bool requiresClass() const;
LayoutConstraint getLayoutConstraint() const;
/// Return the Swift type which provides structure for this
/// abstraction pattern.
///
/// This is always valid unless the pattern is opaque or an
/// open-coded tuple. However, it does not always fully describe
/// the abstraction pattern.
CanType getType() const {
switch (getKind()) {
case Kind::Invalid:
llvm_unreachable("querying invalid abstraction pattern!");
case Kind::Opaque:
llvm_unreachable("opaque pattern has no type");
case Kind::Tuple:
llvm_unreachable("open-coded tuple pattern has no type");
case Kind::OpaqueFunction:
llvm_unreachable("opaque function pattern has no type");
case Kind::OpaqueDerivativeFunction:
llvm_unreachable("opaque derivative function pattern has no type");
case Kind::ClangType:
case Kind::ObjCCompletionHandlerArgumentsType:
case Kind::CurriedObjCMethodType:
case Kind::PartialCurriedObjCMethodType:
case Kind::ObjCMethodType:
case Kind::CFunctionAsMethodType:
case Kind::CurriedCFunctionAsMethodType:
case Kind::PartialCurriedCFunctionAsMethodType:
case Kind::CXXMethodType:
case Kind::CurriedCXXMethodType:
case Kind::PartialCurriedCXXMethodType:
case Kind::CXXOperatorMethodType:
case Kind::CurriedCXXOperatorMethodType:
case Kind::PartialCurriedCXXOperatorMethodType:
case Kind::Type:
case Kind::Discard:
return OrigType;
}
llvm_unreachable("bad kind");
}
/// Do the two given types have the same basic type structure as
/// far as abstraction patterns are concerned?
///
/// Type structure means tuples, functions, and optionals should
/// appear in the same positions.
static bool hasSameBasicTypeStructure(CanType l, CanType r);
/// Rewrite the type of this abstraction pattern without otherwise
/// changing its structure. It is only valid to do this on a pattern
/// that already stores a type, and the new type must have the same
/// basic type structure as the old one.
void rewriteType(CanGenericSignature signature, CanType type) {
switch (getKind()) {
case Kind::Invalid:
case Kind::Opaque:
case Kind::Tuple:
case Kind::OpaqueFunction:
case Kind::OpaqueDerivativeFunction:
llvm_unreachable("type cannot be replaced on pattern without type");
case Kind::ClangType:
case Kind::CurriedObjCMethodType:
case Kind::PartialCurriedObjCMethodType:
case Kind::ObjCMethodType:
case Kind::CFunctionAsMethodType:
case Kind::CurriedCFunctionAsMethodType:
case Kind::PartialCurriedCFunctionAsMethodType:
case Kind::CXXMethodType:
case Kind::CurriedCXXMethodType:
case Kind::PartialCurriedCXXMethodType:
case Kind::CXXOperatorMethodType:
case Kind::CurriedCXXOperatorMethodType:
case Kind::PartialCurriedCXXOperatorMethodType:
case Kind::Type:
case Kind::Discard:
case Kind::ObjCCompletionHandlerArgumentsType:
assert(signature || !type->hasTypeParameter());
assert(hasSameBasicTypeStructure(OrigType, type));
GenericSig = (type->hasTypeParameter() ? signature : nullptr);
OrigType = type;
return;
}
llvm_unreachable("bad kind");
}
/// Return whether this abstraction pattern contains foreign type
/// information.
///
/// In general, after eliminating tuples, a foreign abstraction
/// pattern will satisfy either isClangType() or isObjCMethod().
bool isForeign() const {
switch (getKind()) {
case Kind::Invalid:
llvm_unreachable("querying invalid abstraction pattern!");
case Kind::Opaque:
case Kind::Tuple:
case Kind::Type:
case Kind::Discard:
case Kind::OpaqueFunction:
case Kind::OpaqueDerivativeFunction:
return false;
case Kind::ClangType:
case Kind::PartialCurriedObjCMethodType:
case Kind::CurriedObjCMethodType:
case Kind::ObjCMethodType:
case Kind::CFunctionAsMethodType:
case Kind::CurriedCFunctionAsMethodType:
case Kind::PartialCurriedCFunctionAsMethodType:
case Kind::CXXMethodType:
case Kind::CurriedCXXMethodType:
case Kind::PartialCurriedCXXMethodType:
case Kind::CXXOperatorMethodType:
case Kind::CurriedCXXOperatorMethodType:
case Kind::PartialCurriedCXXOperatorMethodType:
case Kind::ObjCCompletionHandlerArgumentsType:
return true;
}
llvm_unreachable("bad kind");
}
/// True if the value is discarded.
bool isDiscarded() const {
return getKind() == Kind::Discard;
}
/// Return whether this abstraction pattern represents a Clang type.
/// If so, it is legal to return getClangType().
bool isClangType() const {
return (getKind() == Kind::ClangType);
}
const clang::Type *getClangType() const {
assert(hasStoredClangType());
return ClangType;
}
/// Return whether this abstraction pattern represents an
/// Objective-C method. If so, it is legal to call getObjCMethod().
bool isObjCMethod() const {
return (getKind() == Kind::ObjCMethodType ||
getKind() == Kind::CurriedObjCMethodType);
}
const clang::ObjCMethodDecl *getObjCMethod() const {
assert(hasStoredObjCMethod());
return ObjCMethod;
}
/// Return whether this abstraction pattern represents a C++ method.
/// If so, it is legal to call getCXXMethod().
bool isCXXMethod() const {
return (getKind() == Kind::CXXMethodType ||
getKind() == Kind::CurriedCXXMethodType ||
getKind() == Kind::CXXOperatorMethodType ||
getKind() == Kind::CurriedCXXOperatorMethodType);
}
const clang::CXXMethodDecl *getCXXMethod() const {
assert(hasStoredCXXMethod());
return CXXMethod;
}
bool isOpaqueFunctionOrOpaqueDerivativeFunction() const {
return (getKind() == Kind::OpaqueFunction ||
getKind() == Kind::OpaqueDerivativeFunction);
}
EncodedForeignInfo getEncodedForeignInfo() const {
assert(hasStoredForeignInfo());
return EncodedForeignInfo::fromOpaqueValue(OtherData);
}
bool hasForeignErrorStrippingResultOptionality() const {
switch (getKind()) {
case Kind::Invalid:
llvm_unreachable("querying invalid abstraction pattern!");
case Kind::Tuple:
llvm_unreachable("querying foreign-error bits on non-function pattern");
case Kind::Opaque:
case Kind::ClangType:
case Kind::Type:
case Kind::Discard:
case Kind::CFunctionAsMethodType:
case Kind::CurriedCFunctionAsMethodType:
case Kind::PartialCurriedCFunctionAsMethodType:
case Kind::CXXMethodType:
case Kind::CurriedCXXMethodType:
case Kind::PartialCurriedCXXMethodType:
case Kind::CXXOperatorMethodType:
case Kind::CurriedCXXOperatorMethodType:
case Kind::PartialCurriedCXXOperatorMethodType:
case Kind::OpaqueFunction:
case Kind::OpaqueDerivativeFunction:
case Kind::ObjCCompletionHandlerArgumentsType:
return false;
case Kind::PartialCurriedObjCMethodType:
case Kind::CurriedObjCMethodType:
case Kind::ObjCMethodType: {
auto errorInfo = getEncodedForeignInfo();
return errorInfo.errorStripsResultOptionality();
}
}
llvm_unreachable("bad kind");
}
template<typename TYPE>
typename CanTypeWrapperTraits<TYPE>::type
getAs() const {
switch (getKind()) {
case Kind::Invalid:
llvm_unreachable("querying invalid abstraction pattern!");
case Kind::Opaque:
return typename CanTypeWrapperTraits<TYPE>::type();
case Kind::Tuple:
return typename CanTypeWrapperTraits<TYPE>::type();
case Kind::OpaqueFunction:
case Kind::OpaqueDerivativeFunction:
return typename CanTypeWrapperTraits<TYPE>::type();
case Kind::ClangType:
case Kind::PartialCurriedObjCMethodType:
case Kind::CurriedObjCMethodType:
case Kind::ObjCMethodType:
case Kind::CFunctionAsMethodType:
case Kind::CurriedCFunctionAsMethodType:
case Kind::PartialCurriedCFunctionAsMethodType:
case Kind::CXXMethodType:
case Kind::CurriedCXXMethodType:
case Kind::PartialCurriedCXXMethodType:
case Kind::CXXOperatorMethodType:
case Kind::CurriedCXXOperatorMethodType:
case Kind::PartialCurriedCXXOperatorMethodType:
case Kind::Type:
case Kind::Discard:
case Kind::ObjCCompletionHandlerArgumentsType:
return dyn_cast<TYPE>(getType());
}
llvm_unreachable("bad kind");
}
/// Is this pattern the exact given type?
///
/// This is only useful for avoiding redundant work at compile time;
/// code should be prepared to do the right thing in the face of a slight
/// mismatch. This may happen for any number of reasons.
bool isExactType(CanType type) const {
switch (getKind()) {
case Kind::Invalid:
llvm_unreachable("querying invalid abstraction pattern!");
case Kind::Opaque:
case Kind::Tuple:
case Kind::ClangType:
case Kind::PartialCurriedObjCMethodType:
case Kind::CurriedObjCMethodType:
case Kind::ObjCMethodType:
case Kind::CFunctionAsMethodType:
case Kind::CurriedCFunctionAsMethodType:
case Kind::PartialCurriedCFunctionAsMethodType:
case Kind::CXXMethodType:
case Kind::CurriedCXXMethodType:
case Kind::PartialCurriedCXXMethodType:
case Kind::CXXOperatorMethodType:
case Kind::CurriedCXXOperatorMethodType:
case Kind::PartialCurriedCXXOperatorMethodType:
case Kind::OpaqueFunction:
case Kind::OpaqueDerivativeFunction:
case Kind::ObjCCompletionHandlerArgumentsType:
// We assume that the Clang type might provide additional structure.
return false;
case Kind::Type:
case Kind::Discard:
return getType() == type;
}
llvm_unreachable("bad kind");
}
/// Is the given tuple type a valid substitution of this abstraction
/// pattern?
bool matchesTuple(CanTupleType substType);
bool isTuple() {
switch (getKind()) {
case Kind::Invalid:
llvm_unreachable("querying invalid abstraction pattern!");
case Kind::Opaque:
case Kind::PartialCurriedObjCMethodType:
case Kind::CurriedObjCMethodType:
case Kind::CFunctionAsMethodType:
case Kind::CurriedCFunctionAsMethodType:
case Kind::PartialCurriedCFunctionAsMethodType:
case Kind::ObjCMethodType:
case Kind::CXXMethodType:
case Kind::CurriedCXXMethodType:
case Kind::PartialCurriedCXXMethodType:
case Kind::CXXOperatorMethodType:
case Kind::CurriedCXXOperatorMethodType:
case Kind::PartialCurriedCXXOperatorMethodType:
case Kind::OpaqueFunction:
case Kind::OpaqueDerivativeFunction:
return false;
case Kind::ObjCCompletionHandlerArgumentsType:
case Kind::Tuple:
return true;
case Kind::Type:
case Kind::Discard:
case Kind::ClangType:
return isa<TupleType>(getType());
}
llvm_unreachable("bad kind");
}
size_t getNumTupleElements() const {
switch (getKind()) {
case Kind::Invalid:
llvm_unreachable("querying invalid abstraction pattern!");
case Kind::Opaque:
case Kind::PartialCurriedObjCMethodType:
case Kind::CurriedObjCMethodType:
case Kind::CFunctionAsMethodType:
case Kind::CurriedCFunctionAsMethodType:
case Kind::PartialCurriedCFunctionAsMethodType:
case Kind::ObjCMethodType:
case Kind::CXXMethodType:
case Kind::CurriedCXXMethodType:
case Kind::PartialCurriedCXXMethodType:
case Kind::CXXOperatorMethodType:
case Kind::CurriedCXXOperatorMethodType:
case Kind::PartialCurriedCXXOperatorMethodType:
case Kind::OpaqueFunction:
case Kind::OpaqueDerivativeFunction:
llvm_unreachable("pattern is not a tuple");
case Kind::Tuple:
return getNumTupleElements_Stored();
case Kind::ObjCCompletionHandlerArgumentsType:
case Kind::Type:
case Kind::Discard:
case Kind::ClangType:
return cast<TupleType>(getType())->getNumElements();
}
llvm_unreachable("bad kind");
}
/// Given that the value being abstracted is a tuple type, return
/// the abstraction pattern for its object type.
AbstractionPattern getTupleElementType(unsigned index) const;
/// Given that the value being abstracted is a function, return the
/// abstraction pattern for its result type.
AbstractionPattern getFunctionResultType() const;
/// Given that the value being abstracted is a function type, return
/// the abstraction pattern for one of its parameter types.
AbstractionPattern getFunctionParamType(unsigned index) const;
/// Given that the value being abstracted is a function type, return
/// the number of parameters.
unsigned getNumFunctionParams() const;
/// Given that the value being abstracted is optional, return the
/// abstraction pattern for its object type.
AbstractionPattern getOptionalObjectType() const;
/// If this pattern refers to a reference storage type, look through
/// it.
AbstractionPattern getReferenceStorageReferentType() const;
/// Given that the value being abstracted is a function type, return the
/// abstraction pattern for the derivative function.
///
/// The arguments are the same as the arguments to
/// `AnyFunctionType::getAutoDiffDerivativeFunctionType()`.
AbstractionPattern getAutoDiffDerivativeFunctionType(
IndexSubset *parameterIndices, AutoDiffDerivativeFunctionKind kind,
LookupConformanceFn lookupConformance,
GenericSignature derivativeGenericSignature = GenericSignature(),
bool makeSelfParamFirst = false);
/// If this pattern refers to a foreign ObjC method that was imported as async, this returns
/// the abstraction pattern for the completion callback with the original ObjC block type.
///
/// Otherwise, this produces the default fully-concrete abstraction pattern for the given
/// Swift type.
AbstractionPattern getObjCMethodAsyncCompletionHandlerType(
CanType swiftCompletionHandlerType) const;
void dump() const LLVM_ATTRIBUTE_USED;
void print(raw_ostream &OS) const;
};
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &out,
const AbstractionPattern &pattern) {
pattern.print(out);
return out;
}
}
}
#endif