mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
When a generic function has potentially Escapable outputs, those outputs declare lifetime dependencies, which have no effect when substitution leads to those types becoming `Escapable` in a concrete context. This means that type substitution should canonically eliminate lifetime dependencies targeting Escapable parameters or returns, and that type checking should allow a function value with potentially-Escapable lifetime dependencies to bind to a function type without those dependencies when the target of the dependencies is Escapable. Fixes rdar://147533059.
1724 lines
64 KiB
C++
1724 lines
64 KiB
C++
//===--- 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/Basic/IndexedViewRange.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 {
|
|
class FunctionParamGenerator;
|
|
class TupleElementGenerator;
|
|
class PackElementGenerator;
|
|
|
|
/// 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,
|
|
/// 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,
|
|
};
|
|
|
|
enum {
|
|
AsyncCompletionParameterIndexMask = 0xFFEu,
|
|
AsyncCompletionParameterIndexShift = 1,
|
|
|
|
AsyncCompletionErrorParameterIndexMask = 0x1FF000u,
|
|
AsyncCompletionErrorParameterIndexShift = 12,
|
|
|
|
AsyncCompletionErrorFlagParameterIndexMask = 0x3FE00000u,
|
|
AsyncCompletionErrorFlagParameterIndexShift = 21,
|
|
|
|
AsyncCompletionErrorFlagParameterPolarityMask = 0x40000000u,
|
|
AsyncCompletionErrorFlagParameterPolarityShift = 30,
|
|
};
|
|
|
|
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,
|
|
std::optional<unsigned> completionErrorParameterIndex,
|
|
std::optional<unsigned> completionErrorFlagParameterIndex,
|
|
bool completionErrorFlagIsZeroOnError)
|
|
: Value(1 + (unsigned(IsAsync) - 1) +
|
|
(unsigned(completionParameterIndex)
|
|
<< AsyncCompletionParameterIndexShift) +
|
|
((completionErrorParameterIndex
|
|
? *completionErrorParameterIndex + 1
|
|
: 0)
|
|
<< AsyncCompletionErrorParameterIndexShift) +
|
|
((completionErrorFlagParameterIndex
|
|
? *completionErrorFlagParameterIndex + 1
|
|
: 0)
|
|
<< AsyncCompletionErrorFlagParameterIndexShift) +
|
|
(unsigned(completionErrorFlagIsZeroOnError)
|
|
<< AsyncCompletionErrorFlagParameterPolarityShift)) {
|
|
|
|
assert(getKind() == IsAsync);
|
|
assert(getAsyncCompletionHandlerParamIndex() ==
|
|
completionParameterIndex);
|
|
assert(getAsyncCompletionHandlerErrorParamIndex() ==
|
|
completionErrorParameterIndex);
|
|
assert(getAsyncCompletionHandlerErrorFlagParamIndex() ==
|
|
completionErrorFlagParameterIndex);
|
|
assert(isCompletionErrorFlagZeroOnError() ==
|
|
completionErrorFlagIsZeroOnError);
|
|
}
|
|
|
|
public:
|
|
static EncodedForeignInfo
|
|
encode(const std::optional<ForeignErrorConvention> &foreignError,
|
|
const std::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) & AsyncCompletionParameterIndexMask)
|
|
>> AsyncCompletionParameterIndexShift;
|
|
}
|
|
|
|
std::optional<unsigned> getAsyncCompletionHandlerErrorParamIndex() const {
|
|
assert(getKind() == IsAsync);
|
|
|
|
unsigned encodedValue = ((Value - 1) & AsyncCompletionErrorParameterIndexMask)
|
|
>> AsyncCompletionErrorParameterIndexShift;
|
|
if (encodedValue == 0) {
|
|
return std::nullopt;
|
|
}
|
|
return encodedValue - 1;
|
|
}
|
|
|
|
std::optional<unsigned>
|
|
getAsyncCompletionHandlerErrorFlagParamIndex() const {
|
|
assert(getKind() == IsAsync);
|
|
|
|
unsigned encodedValue = ((Value - 1) & AsyncCompletionErrorFlagParameterIndexMask)
|
|
>> AsyncCompletionErrorFlagParameterIndexShift;
|
|
if (encodedValue == 0) {
|
|
return std::nullopt;
|
|
}
|
|
return encodedValue - 1;
|
|
}
|
|
|
|
bool isCompletionErrorFlagZeroOnError() const {
|
|
assert(getKind() == IsAsync);
|
|
|
|
return (Value - 1) & AsyncCompletionErrorFlagParameterPolarityMask;
|
|
}
|
|
|
|
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;
|
|
const void *RawTypePtr;
|
|
};
|
|
CanGenericSignature GenericSig;
|
|
SubstitutionMap GenericSubs;
|
|
|
|
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:
|
|
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:
|
|
case Kind::CXXMethodType:
|
|
case Kind::CurriedCXXMethodType:
|
|
case Kind::PartialCurriedCXXMethodType:
|
|
return true;
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void initSwiftType(SubstitutionMap subs,
|
|
CanGenericSignature signature,
|
|
CanType origType,
|
|
Kind kind = Kind::Type) {
|
|
assert(signature || !origType->hasTypeParameter());
|
|
TheKind = unsigned(kind);
|
|
OrigType = origType;
|
|
GenericSig = CanGenericSignature();
|
|
GenericSubs = subs;
|
|
if (OrigType->hasTypeParameter()) {
|
|
assert(OrigType == signature.getReducedType(origType));
|
|
GenericSig = signature;
|
|
}
|
|
}
|
|
|
|
void initClangType(SubstitutionMap subs, CanGenericSignature signature,
|
|
CanType origType, const clang::Type *clangType,
|
|
Kind kind = Kind::ClangType) {
|
|
initSwiftType(subs, signature, origType, kind);
|
|
ClangType = clangType;
|
|
}
|
|
|
|
void initObjCMethod(SubstitutionMap subs, CanGenericSignature signature,
|
|
CanType origType, const clang::ObjCMethodDecl *method,
|
|
Kind kind, EncodedForeignInfo errorInfo) {
|
|
initSwiftType(subs, signature, origType, kind);
|
|
ObjCMethod = method;
|
|
OtherData = errorInfo.getOpaqueValue();
|
|
}
|
|
|
|
void initCFunctionAsMethod(SubstitutionMap subs,
|
|
CanGenericSignature signature,
|
|
CanType origType, const clang::Type *clangType,
|
|
Kind kind,
|
|
ImportAsMemberStatus memberStatus) {
|
|
initClangType(subs, signature, origType, clangType, kind);
|
|
OtherData = memberStatus.getRawValue();
|
|
}
|
|
|
|
void initCXXMethod(SubstitutionMap subs,
|
|
CanGenericSignature signature, CanType origType,
|
|
const clang::CXXMethodDecl *method, Kind kind,
|
|
ImportAsMemberStatus memberStatus) {
|
|
initSwiftType(subs, signature, origType, kind);
|
|
CXXMethod = method;
|
|
OtherData = memberStatus.getRawValue();
|
|
}
|
|
|
|
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(SubstitutionMap(), signature, origType);
|
|
}
|
|
explicit AbstractionPattern(SubstitutionMap subs, CanType origType) {
|
|
initSwiftType(subs, subs.getGenericSignature().getCanonicalSignature(),
|
|
origType);
|
|
}
|
|
explicit AbstractionPattern(SubstitutionMap subs, CanGenericSignature sig,
|
|
CanType origType) {
|
|
initSwiftType(subs, sig, origType);
|
|
}
|
|
explicit AbstractionPattern(CanType origType, const clang::Type *clangType)
|
|
: AbstractionPattern(nullptr, origType, clangType) {}
|
|
explicit AbstractionPattern(CanGenericSignature signature, CanType origType,
|
|
const clang::Type *clangType) {
|
|
initClangType(SubstitutionMap(), signature, origType, clangType);
|
|
}
|
|
explicit AbstractionPattern(SubstitutionMap subs,
|
|
CanGenericSignature signature,
|
|
CanType origType,
|
|
const clang::Type *clangType) {
|
|
initClangType(subs, 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::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");
|
|
}
|
|
|
|
SubstitutionMap getGenericSubstitutions() const {
|
|
return GenericSubs;
|
|
}
|
|
|
|
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(SubstitutionMap subs,
|
|
CanGenericSignature sig,
|
|
CanType origTupleType,
|
|
const clang::Type *clangBlockType,
|
|
EncodedForeignInfo foreignInfo) {
|
|
AbstractionPattern pattern(Kind::ObjCCompletionHandlerArgumentsType);
|
|
pattern.initClangType(subs, 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 std::optional<ForeignErrorConvention> &foreignError,
|
|
const std::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 CCRefrigeratorSetTemperature(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(SubstitutionMap(), 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 CCRefrigeratorSetTemperature(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);
|
|
|
|
/// 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,
|
|
ImportAsMemberStatus memberStatus) {
|
|
assert(isa<AnyFunctionType>(origType));
|
|
AbstractionPattern pattern;
|
|
pattern.initCXXMethod(SubstitutionMap(), nullptr, origType, method,
|
|
Kind::CXXMethodType, memberStatus);
|
|
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,
|
|
ImportAsMemberStatus memberStatus) {
|
|
assert(isa<AnyFunctionType>(origType));
|
|
AbstractionPattern pattern;
|
|
pattern.initCXXMethod(SubstitutionMap(), nullptr, origType, method,
|
|
Kind::CurriedCXXMethodType, memberStatus);
|
|
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(SubstitutionMap subs,
|
|
CanGenericSignature signature,
|
|
CanType origType) {
|
|
AbstractionPattern pattern;
|
|
pattern.initSwiftType(subs, 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,
|
|
SubstitutionMap subMap) 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(SubstitutionMap(), 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(SubstitutionMap(), 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(SubstitutionMap subs,
|
|
CanGenericSignature signature,
|
|
CanType origType,
|
|
const clang::ObjCMethodDecl *method,
|
|
EncodedForeignInfo errorInfo) {
|
|
assert(isa<AnyFunctionType>(origType));
|
|
AbstractionPattern pattern;
|
|
pattern.initObjCMethod(subs, 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:
|
|
/// CCRefrigeratorSetTemperature(CCRefrigeratorRef, CCTemperature)
|
|
/// then the curried type is:
|
|
/// (CCRefrigerator) -> (CCTemperature) -> ()
|
|
/// and the partially-applied curried type is:
|
|
/// (CCTemperature) -> ()
|
|
static AbstractionPattern
|
|
getPartialCurriedCFunctionAsMethod(SubstitutionMap subs,
|
|
CanGenericSignature signature,
|
|
CanType origType,
|
|
const clang::Type *clangType,
|
|
ImportAsMemberStatus memberStatus) {
|
|
assert(isa<AnyFunctionType>(origType));
|
|
AbstractionPattern pattern;
|
|
pattern.initCFunctionAsMethod(subs, 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(SubstitutionMap subs,
|
|
CanGenericSignature signature, CanType origType,
|
|
const clang::CXXMethodDecl *method,
|
|
ImportAsMemberStatus memberStatus) {
|
|
assert(isa<AnyFunctionType>(origType));
|
|
AbstractionPattern pattern;
|
|
pattern.initCXXMethod(subs, signature, origType, method,
|
|
Kind::PartialCurriedCXXMethodType, memberStatus);
|
|
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 std::optional<ForeignErrorConvention> &foreignError,
|
|
const std::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(SubstitutionMap(), 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.
|
|
//
|
|
// Even if we support Clang nodes someday, we *cannot* cache
|
|
// by the open-coded patterns like Tuple.
|
|
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) ||
|
|
isa<PackElementType>(type) ||
|
|
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) ||
|
|
isa<PackElementType>(type)) {
|
|
return true;
|
|
}
|
|
if (auto archetype = dyn_cast<ArchetypeType>(type)) {
|
|
return !isa<OpaqueTypeArchetypeType>(archetype);
|
|
}
|
|
return false;
|
|
}
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool isTypeParameterPack() const {
|
|
switch (getKind()) {
|
|
case Kind::Opaque:
|
|
return false;
|
|
case Kind::Type:
|
|
case Kind::ClangType:
|
|
case Kind::Discard: {
|
|
auto ty = getType();
|
|
return isa<PackArchetypeType>(ty) || ty->isParameterPack();
|
|
}
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool isPackExpansion() const {
|
|
switch (getKind()) {
|
|
case Kind::Type:
|
|
case Kind::Discard:
|
|
return isa<PackExpansionType>(getType());
|
|
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;
|
|
bool conformsToKnownProtocol(
|
|
CanType substTy, KnownProtocolKind protocolKind) const;
|
|
bool isNoncopyable(CanType substTy) const;
|
|
bool isEscapable(CanType substTy) 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::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::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");
|
|
}
|
|
|
|
/// Add substitutions to this pattern.
|
|
AbstractionPattern withSubstitutions(SubstitutionMap subs) const {
|
|
AbstractionPattern result = *this;
|
|
if (subs) {
|
|
// If we have a generic signature, it should match the substitutions.
|
|
// But in corner cases, "match" can mean that it applies to an inner
|
|
// local generic context, which is not something we can easily assert.
|
|
result.GenericSubs = subs;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/// 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::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);
|
|
}
|
|
|
|
const clang::CXXMethodDecl *getCXXMethod() const {
|
|
assert(hasStoredCXXMethod());
|
|
return CXXMethod;
|
|
}
|
|
|
|
bool isOpaqueTuple() const {
|
|
return getKind() == Kind::Tuple;
|
|
}
|
|
|
|
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::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:
|
|
case Kind::Tuple:
|
|
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::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::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? Note that the type doesn't have to be a tuple type in the
|
|
/// case of a vanishing tuple.
|
|
bool matchesTuple(CanType substType) const;
|
|
|
|
bool isTuple() 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::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::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");
|
|
}
|
|
|
|
bool doesTupleContainPackExpansionType() const;
|
|
|
|
/// If this type is a tuple type that vanishes (is flattened to its
|
|
/// singleton non-expansion element) under the stored substitutions,
|
|
/// return the abstraction pattern of the surviving element.
|
|
///
|
|
/// If the surviving element came from an expansion element, the
|
|
/// returned element is the pattern type of the expansion.
|
|
std::optional<AbstractionPattern> getVanishingTupleElementPatternType() const;
|
|
|
|
/// Does this tuple type vanish, i.e. is it flattened to a singleton
|
|
/// non-expansion element under substitution?
|
|
bool doesTupleVanish() const;
|
|
|
|
static AbstractionPattern
|
|
projectTupleElementType(const AbstractionPattern *base, size_t index) {
|
|
return base->getTupleElementType(index);
|
|
}
|
|
|
|
IndexedViewRange<const AbstractionPattern *, AbstractionPattern,
|
|
projectTupleElementType> getTupleElementTypes() const {
|
|
assert(isTuple());
|
|
return { { this, 0 }, { this, getNumTupleElements() } };
|
|
}
|
|
|
|
/// Perform a parallel visitation of the elements of a tuple type,
|
|
/// preserving structure about where pack expansions appear in the
|
|
/// original type and how many elements of the substituted type they
|
|
/// expand to.
|
|
///
|
|
/// This pattern must be a tuple pattern. The substituted type may be
|
|
/// a non-tuple only if this is a vanshing tuple pattern.
|
|
void forEachTupleElement(CanType substType,
|
|
llvm::function_ref<void(TupleElementGenerator &element)> fn) const;
|
|
|
|
/// Perform a parallel visitation of the elements of a tuple type,
|
|
/// expanding the elements of the type. This preserves the structure
|
|
/// of the *substituted* tuple type: it will be called once per element
|
|
/// of the substituted type, in order. The original element trappings
|
|
/// are also provided for convenience.
|
|
///
|
|
/// This pattern must match the substituted type, but it may be an
|
|
/// opaque pattern.
|
|
void forEachExpandedTupleElement(CanType substType,
|
|
llvm::function_ref<void(AbstractionPattern origEltType,
|
|
CanType substEltType,
|
|
const TupleTypeElt &elt)> handleElement) const;
|
|
|
|
/// Is the given pack type a valid substitution of this abstraction
|
|
/// pattern?
|
|
bool matchesPack(CanPackType substType) const;
|
|
|
|
bool isPack() 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::OpaqueFunction:
|
|
case Kind::OpaqueDerivativeFunction:
|
|
case Kind::ObjCCompletionHandlerArgumentsType:
|
|
case Kind::Tuple:
|
|
case Kind::ClangType:
|
|
return false;
|
|
case Kind::Type:
|
|
case Kind::Discard:
|
|
return isa<PackType>(getType());
|
|
}
|
|
llvm_unreachable("bad kind");
|
|
}
|
|
|
|
size_t getNumPackElements() 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::OpaqueFunction:
|
|
case Kind::OpaqueDerivativeFunction:
|
|
case Kind::ObjCCompletionHandlerArgumentsType:
|
|
case Kind::Tuple:
|
|
case Kind::ClangType:
|
|
llvm_unreachable("pattern is not a pack");
|
|
case Kind::Type:
|
|
case Kind::Discard:
|
|
return cast<PackType>(getType())->getNumElements();
|
|
}
|
|
llvm_unreachable("bad kind");
|
|
}
|
|
|
|
/// Perform a parallel visitation of the elements of a pack type,
|
|
/// preserving structure about where pack expansions appear in the
|
|
/// original type and how many elements of the substituted type they
|
|
/// expand to.
|
|
///
|
|
/// This pattern must be a pack pattern.
|
|
void forEachPackElement(CanPackType substPackType,
|
|
llvm::function_ref<void(PackElementGenerator &element)> fn) const;
|
|
|
|
/// Perform a parallel visitation of the elements of a pack type,
|
|
/// expanding the elements of the type. This preserves the structure
|
|
/// of the *substituted* pack type: it will be called once per element
|
|
/// of the substituted type, in order.
|
|
///
|
|
/// This pattern must match the substituted type, but it may be an
|
|
/// opaque pattern.
|
|
void forEachExpandedPackElement(CanPackType substPackType,
|
|
llvm::function_ref<void(AbstractionPattern origEltType,
|
|
CanType substEltType)> handleElement) const;
|
|
|
|
/// Given that the value being abstracted is a move only type, return the
|
|
/// abstraction pattern with the move only bit removed.
|
|
AbstractionPattern removingMoveOnlyWrapper() const;
|
|
|
|
/// Given that the value being abstracted is not a move only type, return the
|
|
/// abstraction pattern with the move only bit added.
|
|
AbstractionPattern addingMoveOnlyWrapper() const;
|
|
|
|
/// Given that the value being abstracted is a tuple type, return
|
|
/// the abstraction pattern for an element type.
|
|
AbstractionPattern getTupleElementType(unsigned index) const;
|
|
|
|
/// Given that the value being abstracted is a pack element type, return
|
|
/// the abstraction pattern for its pack type.
|
|
AbstractionPattern getPackElementPackType() const;
|
|
|
|
/// Given that the value being abstracted is a pack type, return
|
|
/// the abstraction pattern for an element type.
|
|
AbstractionPattern getPackElementType(unsigned index) const;
|
|
|
|
/// Given that the value being abstracted is a pack expansion type,
|
|
/// return the underlying pattern type.
|
|
AbstractionPattern getPackExpansionPatternType() const;
|
|
|
|
/// Given that the value being abstracted is a pack expansion type,
|
|
/// return the underlying count type.
|
|
AbstractionPattern getPackExpansionCountType() const;
|
|
|
|
/// Given that the value being abstracted is a pack expansion type,
|
|
/// return the appropriate pattern type for the given expansion
|
|
/// component.
|
|
AbstractionPattern getPackExpansionComponentType(CanType substType) const;
|
|
AbstractionPattern getPackExpansionComponentType(bool isExpansion) const;
|
|
|
|
/// Given that the value being abstracted is a metatype type, return
|
|
/// the abstraction pattern for its instance type.
|
|
AbstractionPattern getMetatypeInstanceType() const;
|
|
|
|
/// Given that the value being abstracted is a dynamic self type, return
|
|
/// the abstraction pattern for its self type.
|
|
AbstractionPattern getDynamicSelfSelfType() const;
|
|
|
|
/// Given that the value being abstracted is a protocol composition
|
|
/// type, return the abstraction pattern for one of its member types.
|
|
AbstractionPattern getProtocolCompositionMemberType(unsigned i) const;
|
|
|
|
/// Given that the value being abstracted is a parameterized protocol
|
|
/// type, return the abstraction pattern for one of its argument types.
|
|
AbstractionPattern getParameterizedProtocolArgType(unsigned i) 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, return the
|
|
/// abstraction pattern for its thrown error type.
|
|
std::optional<AbstractionPattern> getFunctionThrownErrorType() const;
|
|
|
|
/// Utility method to adjust a thrown error pattern and thrown error type
|
|
/// to account for some quirks in type lowering.
|
|
///
|
|
/// When lowered with an opaque pattern,
|
|
///
|
|
/// - () -> () becomes () -> (),
|
|
/// - () throws(any Error) -> () becomes () -> (@error any Error),
|
|
///
|
|
/// *not* () -> (@error_indirect Never) or () -> (@error_indirect any Error).
|
|
std::optional<std::pair<AbstractionPattern, CanType>>
|
|
getFunctionThrownErrorType(CanAnyFunctionType substFnInterfaceType) const;
|
|
|
|
/// For the abstraction pattern produced by `getFunctionThrownErrorType()`,
|
|
/// produce the effective thrown error type to be used when we don't have
|
|
/// a substituted error type.
|
|
CanType getEffectiveThrownErrorType() 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, and that
|
|
/// this is not an opaque abstraction pattern, return the parameter flags
|
|
/// for one of its parameters.
|
|
ParameterTypeFlags getFunctionParamFlags(unsigned index) const;
|
|
|
|
/// Given that the value being abstracted is a function type, return whether
|
|
/// the indicated parameter should be treated as addressable, meaning
|
|
/// calls should preserve the in-memory address of the argument for as
|
|
/// long as any dependencies may live.
|
|
///
|
|
/// This may be true either because the type is structurally addressable for
|
|
/// dependencies, or because it was explicitly marked as `@_addressable`
|
|
/// in its declaration.
|
|
bool isFunctionParamAddressable(unsigned index) const;
|
|
|
|
ArrayRef<LifetimeDependenceInfo> getLifetimeDependencies() const;
|
|
|
|
/// Given that the value being abstracted is a function type, and that
|
|
/// this is not an opaque abstraction pattern, return the number of
|
|
/// parameters in the pattern.
|
|
unsigned getNumFunctionParams() const;
|
|
|
|
/// Traverses the parameters of a function, where this is the
|
|
/// abstraction pattern for the function (its "original type")
|
|
/// and the given parameters are the substituted formal parameters.
|
|
/// Calls the callback once for each parameter in the abstraction
|
|
/// pattern.
|
|
///
|
|
/// If this is not a function pattern, calls handleScalar for each
|
|
/// parameter of the substituted function type. Note that functions
|
|
/// with pack expansions cannot be legally abstracted this way; it
|
|
/// is not possible in Swift's ABI to support this without some sort
|
|
/// of dynamic argument-forwarding thunk.
|
|
void forEachFunctionParam(AnyFunctionType::CanParamArrayRef substParams,
|
|
bool ignoreFinalParam,
|
|
llvm::function_ref<void(FunctionParamGenerator ¶m)> function) const;
|
|
|
|
/// Return the start index of the given formal parameter in the lowered
|
|
/// parameter sequence corresponding to a function with this abstraction
|
|
/// pattern.
|
|
unsigned getLoweredParamIndex(unsigned formalIndex) const;
|
|
|
|
/// If this abstraction pattern is recursively expanded and flattened
|
|
/// in the normal way for parameters and results, how many values does
|
|
/// it correspond to?
|
|
unsigned getFlattenedValueCount() 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;
|
|
|
|
/// Give that the value being abstracted is an existential, return the
|
|
/// underlying constraint type.
|
|
AbstractionPattern getExistentialConstraintType() 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;
|
|
|
|
/// Given that this is a pack expansion, return the number of components
|
|
/// that it should expand to. This, and the general correctness of
|
|
/// traversing variadically generic tuple and function types under
|
|
/// substitution, relies on substitutions having been set properly
|
|
/// on the abstraction pattern; without that, AbstractionPattern assumes
|
|
/// that every component expands to a single pack expansion component,
|
|
/// which will generally only work in specific situations.
|
|
size_t getNumPackExpandedComponents() const;
|
|
|
|
/// If this pattern refers to a foreign ObjC method that was imported as
|
|
/// async, return the bridged-back-to-ObjC completion handler type.
|
|
CanType getObjCMethodAsyncCompletionHandlerForeignType(
|
|
ForeignAsyncConvention convention,
|
|
Lowering::TypeConverter &TC
|
|
) const;
|
|
|
|
/// How values are passed or returned according to this abstraction pattern.
|
|
enum CallingConventionKind {
|
|
// Value is passed or returned directly as a unit.
|
|
Direct,
|
|
// Value is passed or returned indirectly through memory.
|
|
Indirect,
|
|
// Value is a tuple that is destructured, and each element is considered
|
|
// independently.
|
|
Destructured,
|
|
};
|
|
|
|
/// Given that this is a pack expansion, do the pack elements need to be
|
|
/// passed indirectly?
|
|
bool arePackElementsPassedIndirectly(TypeConverter &TC) const;
|
|
|
|
/// If this abstraction pattern appears in function return position, how is
|
|
/// the corresponding value returned?
|
|
CallingConventionKind getResultConvention(TypeConverter &TC) const;
|
|
|
|
/// If this abstraction pattern appears in function parameter position, how
|
|
/// is the corresponding value passed?
|
|
CallingConventionKind getParameterConvention(TypeConverter &TC) const;
|
|
|
|
/// If this abstraction pattern appears in function thrown error position, how
|
|
/// is the corresponding value passed?
|
|
CallingConventionKind getErrorConvention(TypeConverter &TC) const;
|
|
|
|
/// Generate the abstraction pattern for lowering the substituted SIL
|
|
/// function type for a function type matching this abstraction pattern.
|
|
///
|
|
/// This abstraction pattern must be a function abstraction pattern, matching
|
|
/// \c substType .
|
|
///
|
|
/// Where the abstraction pattern involves substitutable types, in order
|
|
/// to minimize function conversions, we extract those positions out into
|
|
/// fresh generic arguments, with the minimum set of constraints necessary
|
|
/// to maintain the calling convention (such as passed-directly or
|
|
/// passed-indirectly) as well as satisfy requirements of where the generic
|
|
/// argument structurally appears in the type.
|
|
/// The goal is for similar-shaped generic function types to remain
|
|
/// canonically equivalent, like `(T, U) -> ()`, `(T, T) -> ()`,
|
|
/// `(U, T) -> ()` or `(T, T.A) -> ()` when given substitutions that produce
|
|
/// the same function types.
|
|
///
|
|
/// Returns a new AbstractionPattern to use for type lowering, as well as
|
|
/// the SubstitutionMap used to map `substType` into the new abstraction
|
|
/// pattern's generic environment, and the coroutine yield type mapped into
|
|
/// the generic environment of the new abstraction pattern.
|
|
std::tuple<AbstractionPattern, SubstitutionMap, AbstractionPattern>
|
|
getSubstFunctionTypePattern(CanAnyFunctionType substType,
|
|
TypeConverter &TC,
|
|
AbstractionPattern coroutineYieldOrigType,
|
|
CanType coroutineYieldSubstType,
|
|
bool &unimplementable) const;
|
|
|
|
void dump() const LLVM_ATTRIBUTE_USED;
|
|
void print(raw_ostream &OS) const;
|
|
|
|
bool operator==(const AbstractionPattern &other) const;
|
|
bool operator!=(const AbstractionPattern &other) const {
|
|
return !(*this == other);
|
|
}
|
|
};
|
|
|
|
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &out,
|
|
const AbstractionPattern &pattern) {
|
|
pattern.print(out);
|
|
return out;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
#endif
|