mirror of
https://github.com/apple/swift.git
synced 2026-06-20 15:42:51 +02:00
Merge pull request #85066 from egorzhdan/egorzhdan/std-function-context
[cxx-interop] Allow initializing `std::function` from Swift capturing closures
This commit is contained in:
@@ -298,6 +298,24 @@ public:
|
||||
|
||||
virtual FuncDecl *getDefaultArgGenerator(const clang::ParmVarDecl *param) = 0;
|
||||
|
||||
/// Determine whether this is a functional C++ type, e.g. std::function, for
|
||||
/// which Swift provides a synthesized constructor that takes a Swift closure
|
||||
/// as the single parameter.
|
||||
virtual bool
|
||||
needsClosureConstructor(const clang::CXXRecordDecl *recordDecl) const = 0;
|
||||
|
||||
/// Determine whether this is an instantiation of the __SwiftFunctionWrapper
|
||||
/// type, which wraps around a Swift closure along with its context.
|
||||
virtual bool isSwiftFunctionWrapper(const clang::RecordDecl *decl) const = 0;
|
||||
virtual bool isDeconstructedSwiftClosure(const clang::Type* type) const = 0;
|
||||
|
||||
/// Given a functional C++ type, e.g. std::function, determine the
|
||||
/// corresponding C++ closure type.
|
||||
///
|
||||
/// \see needsClosureConstructor
|
||||
virtual const clang::FunctionType *extractCXXFunctionType(
|
||||
const clang::CXXRecordDecl *functionalTypeDecl) const = 0;
|
||||
|
||||
virtual FuncDecl *
|
||||
getAvailabilityDomainPredicate(const clang::VarDecl *var) = 0;
|
||||
|
||||
|
||||
@@ -54,6 +54,10 @@ namespace llvm {
|
||||
struct fltSemantics;
|
||||
} // namespace llvm
|
||||
|
||||
namespace clang {
|
||||
class FunctionType;
|
||||
} // namespace clang
|
||||
|
||||
namespace swift {
|
||||
|
||||
enum class AllocationArena;
|
||||
@@ -4101,6 +4105,10 @@ public:
|
||||
return getLifetimeDependenceFor(getNumParams());
|
||||
}
|
||||
|
||||
uint16_t
|
||||
getPointerAuthDiscriminator(ModuleDecl &m,
|
||||
const clang::FunctionType *clangType = nullptr);
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) {
|
||||
std::optional<ExtInfo> info = std::nullopt;
|
||||
if (hasExtInfo())
|
||||
@@ -5949,6 +5957,10 @@ public:
|
||||
bool isReabstractionThunk = false,
|
||||
CanType origTypeOfAbstraction = CanType());
|
||||
|
||||
/// If \p M is nullptr, the type is not substituted.
|
||||
uint16_t getPointerAuthDiscriminator(SILModule *M);
|
||||
|
||||
uint16_t getCoroutineYieldTypesDiscriminator(SILModule &M);
|
||||
|
||||
/// Returns the type of the transpose function for the given parameter
|
||||
/// indices, transpose function generic signature (optional), and other
|
||||
|
||||
@@ -620,6 +620,15 @@ public:
|
||||
|
||||
FuncDecl *getDefaultArgGenerator(const clang::ParmVarDecl *param) override;
|
||||
|
||||
bool needsClosureConstructor(
|
||||
const clang::CXXRecordDecl *recordDecl) const override;
|
||||
|
||||
bool isSwiftFunctionWrapper(const clang::RecordDecl *decl) const override;
|
||||
bool isDeconstructedSwiftClosure(const clang::Type *type) const override;
|
||||
|
||||
const clang::FunctionType *extractCXXFunctionType(
|
||||
const clang::CXXRecordDecl *functionalTypeDecl) const override;
|
||||
|
||||
FuncDecl *getAvailabilityDomainPredicate(const clang::VarDecl *var) override;
|
||||
|
||||
bool isAnnotatedWith(const clang::CXXMethodDecl *method, StringRef attr);
|
||||
|
||||
@@ -28,6 +28,7 @@ namespace llvm {
|
||||
|
||||
namespace clang {
|
||||
class CXXMethodDecl;
|
||||
class CXXRecordDecl;
|
||||
class ObjCMethodDecl;
|
||||
class Type;
|
||||
class ValueDecl;
|
||||
@@ -198,6 +199,10 @@ class AbstractionPattern {
|
||||
/// non-static member function. OrigType is valid and is a function type.
|
||||
/// CXXMethod is valid.
|
||||
PartialCurriedCXXMethodType,
|
||||
/// The type of a constructor that initializes a C++ functional type, e.g.
|
||||
/// std::function, with a Swift closure. This constructor is synthesized by
|
||||
/// ClangImporter. ClangType is valid.
|
||||
CXXFunctionalConstructorType,
|
||||
/// 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.
|
||||
@@ -462,6 +467,7 @@ class AbstractionPattern {
|
||||
case Kind::CFunctionAsMethodType:
|
||||
case Kind::CurriedCFunctionAsMethodType:
|
||||
case Kind::PartialCurriedCFunctionAsMethodType:
|
||||
case Kind::CXXFunctionalConstructorType:
|
||||
case Kind::ObjCCompletionHandlerArgumentsType:
|
||||
return true;
|
||||
|
||||
@@ -632,6 +638,7 @@ public:
|
||||
case Kind::CXXMethodType:
|
||||
case Kind::CurriedCXXMethodType:
|
||||
case Kind::PartialCurriedCXXMethodType:
|
||||
case Kind::CXXFunctionalConstructorType:
|
||||
case Kind::ObjCCompletionHandlerArgumentsType:
|
||||
return true;
|
||||
case Kind::Invalid:
|
||||
@@ -766,6 +773,13 @@ public:
|
||||
return pattern;
|
||||
}
|
||||
|
||||
/// Return an abstraction pattern for a constructor of a functional C++ type,
|
||||
/// e.g. std::function, which takes a Swift closure as a single parameter.
|
||||
/// This constructor was synthesized by ClangImporter.
|
||||
static AbstractionPattern
|
||||
getCXXFunctionalConstructor(CanType origType,
|
||||
const clang::CXXRecordDecl *functionalTypeDecl);
|
||||
|
||||
/// 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
|
||||
@@ -1048,6 +1062,7 @@ public:
|
||||
case Kind::CXXMethodType:
|
||||
case Kind::CurriedCXXMethodType:
|
||||
case Kind::PartialCurriedCXXMethodType:
|
||||
case Kind::CXXFunctionalConstructorType:
|
||||
case Kind::Type:
|
||||
case Kind::Discard:
|
||||
return OrigType;
|
||||
@@ -1084,6 +1099,7 @@ public:
|
||||
case Kind::CXXMethodType:
|
||||
case Kind::CurriedCXXMethodType:
|
||||
case Kind::PartialCurriedCXXMethodType:
|
||||
case Kind::CXXFunctionalConstructorType:
|
||||
case Kind::Type:
|
||||
case Kind::Discard:
|
||||
case Kind::ObjCCompletionHandlerArgumentsType:
|
||||
@@ -1131,6 +1147,7 @@ public:
|
||||
case Kind::CFunctionAsMethodType:
|
||||
case Kind::CurriedCFunctionAsMethodType:
|
||||
case Kind::PartialCurriedCFunctionAsMethodType:
|
||||
case Kind::CXXFunctionalConstructorType:
|
||||
case Kind::CXXMethodType:
|
||||
case Kind::CurriedCXXMethodType:
|
||||
case Kind::PartialCurriedCXXMethodType:
|
||||
@@ -1148,7 +1165,8 @@ public:
|
||||
/// Return whether this abstraction pattern represents a Clang type.
|
||||
/// If so, it is legal to return getClangType().
|
||||
bool isClangType() const {
|
||||
return (getKind() == Kind::ClangType);
|
||||
return getKind() == Kind::ClangType ||
|
||||
getKind() == Kind::CXXFunctionalConstructorType;
|
||||
}
|
||||
|
||||
const clang::Type *getClangType() const {
|
||||
@@ -1211,6 +1229,7 @@ public:
|
||||
case Kind::CXXMethodType:
|
||||
case Kind::CurriedCXXMethodType:
|
||||
case Kind::PartialCurriedCXXMethodType:
|
||||
case Kind::CXXFunctionalConstructorType:
|
||||
case Kind::OpaqueFunction:
|
||||
case Kind::OpaqueDerivativeFunction:
|
||||
case Kind::ObjCCompletionHandlerArgumentsType:
|
||||
@@ -1243,6 +1262,7 @@ public:
|
||||
case Kind::CFunctionAsMethodType:
|
||||
case Kind::CurriedCFunctionAsMethodType:
|
||||
case Kind::PartialCurriedCFunctionAsMethodType:
|
||||
case Kind::CXXFunctionalConstructorType:
|
||||
case Kind::CXXMethodType:
|
||||
case Kind::CurriedCXXMethodType:
|
||||
case Kind::PartialCurriedCXXMethodType:
|
||||
@@ -1275,6 +1295,7 @@ public:
|
||||
case Kind::CXXMethodType:
|
||||
case Kind::CurriedCXXMethodType:
|
||||
case Kind::PartialCurriedCXXMethodType:
|
||||
case Kind::CXXFunctionalConstructorType:
|
||||
case Kind::OpaqueFunction:
|
||||
case Kind::OpaqueDerivativeFunction:
|
||||
case Kind::ObjCCompletionHandlerArgumentsType:
|
||||
@@ -1306,6 +1327,7 @@ public:
|
||||
case Kind::CXXMethodType:
|
||||
case Kind::CurriedCXXMethodType:
|
||||
case Kind::PartialCurriedCXXMethodType:
|
||||
case Kind::CXXFunctionalConstructorType:
|
||||
case Kind::OpaqueFunction:
|
||||
case Kind::OpaqueDerivativeFunction:
|
||||
return false;
|
||||
@@ -1334,6 +1356,7 @@ public:
|
||||
case Kind::CXXMethodType:
|
||||
case Kind::CurriedCXXMethodType:
|
||||
case Kind::PartialCurriedCXXMethodType:
|
||||
case Kind::CXXFunctionalConstructorType:
|
||||
case Kind::OpaqueFunction:
|
||||
case Kind::OpaqueDerivativeFunction:
|
||||
llvm_unreachable("pattern is not a tuple");
|
||||
@@ -1414,6 +1437,7 @@ public:
|
||||
case Kind::CXXMethodType:
|
||||
case Kind::CurriedCXXMethodType:
|
||||
case Kind::PartialCurriedCXXMethodType:
|
||||
case Kind::CXXFunctionalConstructorType:
|
||||
case Kind::OpaqueFunction:
|
||||
case Kind::OpaqueDerivativeFunction:
|
||||
case Kind::ObjCCompletionHandlerArgumentsType:
|
||||
@@ -1441,6 +1465,7 @@ public:
|
||||
case Kind::CXXMethodType:
|
||||
case Kind::CurriedCXXMethodType:
|
||||
case Kind::PartialCurriedCXXMethodType:
|
||||
case Kind::CXXFunctionalConstructorType:
|
||||
case Kind::OpaqueFunction:
|
||||
case Kind::OpaqueDerivativeFunction:
|
||||
case Kind::ObjCCompletionHandlerArgumentsType:
|
||||
|
||||
@@ -999,6 +999,8 @@ public:
|
||||
|
||||
IndexTrieNode *getIndexTrieRoot() { return indexTrieRoot.get(); }
|
||||
|
||||
TypeExpansionContext getMaximalTypeExpansionContext() const;
|
||||
|
||||
/// Can value operations (copies and destroys) on the given lowered type
|
||||
/// be performed in this module?
|
||||
bool isTypeABIAccessible(SILType type,
|
||||
|
||||
@@ -37,6 +37,8 @@ constexpr static const StringLiteral SWIFT_STRING_PROCESSING_NAME = "_StringProc
|
||||
constexpr static const StringLiteral SWIFT_SHIMS_NAME = "SwiftShims";
|
||||
/// The name of the CxxShim module, which contains a cxx casting utility.
|
||||
constexpr static const StringLiteral CXX_SHIM_NAME = "CxxShim";
|
||||
/// The name of the CxxStdlibShim module, which contains utilities for the C++ stdlib overlay.
|
||||
constexpr static const StringLiteral CXX_STDLIB_SHIM_NAME = "CxxStdlibShim";
|
||||
/// The name of the Cxx module, which contains C++ interop helper protocols.
|
||||
constexpr static const StringLiteral CXX_MODULE_NAME = "Cxx";
|
||||
/// The name of the Builtin module, which contains Builtin functions.
|
||||
|
||||
@@ -1180,94 +1180,6 @@ void swift::conformToCxxVectorIfNeeded(ClangImporter::Implementation &impl,
|
||||
impl.addSynthesizedProtocolAttrs(decl, {KnownProtocolKind::CxxVector});
|
||||
}
|
||||
|
||||
void swift::conformToCxxFunctionIfNeeded(
|
||||
ClangImporter::Implementation &impl, NominalTypeDecl *decl,
|
||||
const clang::CXXRecordDecl *clangDecl) {
|
||||
PrettyStackTraceDecl trace("conforming to CxxFunction", decl);
|
||||
|
||||
assert(decl);
|
||||
assert(clangDecl);
|
||||
ASTContext &ctx = decl->getASTContext();
|
||||
clang::ASTContext &clangCtx = impl.getClangASTContext();
|
||||
clang::Sema &clangSema = impl.getClangSema();
|
||||
|
||||
// Only auto-conform types from the C++ standard library. Custom user types
|
||||
// might have a similar interface but different semantics.
|
||||
if (!isStdDecl(clangDecl, {"function"}))
|
||||
return;
|
||||
|
||||
// There is no typealias for the argument types on the C++ side, so to
|
||||
// retrieve the argument types we look at the overload of `operator()` that
|
||||
// got imported into Swift.
|
||||
|
||||
auto callAsFunctionDecl = lookupDirectSingleWithoutExtensions<FuncDecl>(
|
||||
decl, ctx.getIdentifier("callAsFunction"));
|
||||
if (!callAsFunctionDecl)
|
||||
return;
|
||||
|
||||
auto operatorCallDecl = dyn_cast_or_null<clang::CXXMethodDecl>(
|
||||
callAsFunctionDecl->getClangDecl());
|
||||
if (!operatorCallDecl)
|
||||
return;
|
||||
|
||||
std::vector<clang::QualType> operatorCallParamTypes;
|
||||
llvm::transform(
|
||||
operatorCallDecl->parameters(),
|
||||
std::back_inserter(operatorCallParamTypes),
|
||||
[](const clang::ParmVarDecl *paramDecl) { return paramDecl->getType(); });
|
||||
|
||||
auto funcPointerType = clangCtx.getPointerType(clangCtx.getFunctionType(
|
||||
operatorCallDecl->getReturnType(), operatorCallParamTypes,
|
||||
clang::FunctionProtoType::ExtProtoInfo())).withConst();
|
||||
|
||||
// Create a fake variable with a function type that matches the type of
|
||||
// `operator()`.
|
||||
auto fakeFuncPointerVarDecl = clang::VarDecl::Create(
|
||||
clangCtx, /*DC*/ clangCtx.getTranslationUnitDecl(),
|
||||
clang::SourceLocation(), clang::SourceLocation(), /*Id*/ nullptr,
|
||||
funcPointerType, clangCtx.getTrivialTypeSourceInfo(funcPointerType),
|
||||
clang::StorageClass::SC_None);
|
||||
auto fakeFuncPointerRefExpr = new (clangCtx) clang::DeclRefExpr(
|
||||
clangCtx, fakeFuncPointerVarDecl, false, funcPointerType,
|
||||
clang::ExprValueKind::VK_LValue, clang::SourceLocation());
|
||||
|
||||
auto clangDeclTyInfo = clangCtx.getTrivialTypeSourceInfo(
|
||||
clang::QualType(clangDecl->getTypeForDecl(), 0));
|
||||
SmallVector<clang::Expr *, 1> constructExprArgs = {fakeFuncPointerRefExpr};
|
||||
|
||||
// Instantiate the templated constructor that would accept this fake variable.
|
||||
auto constructExprResult = clangSema.BuildCXXTypeConstructExpr(
|
||||
clangDeclTyInfo, clangDecl->getLocation(), constructExprArgs,
|
||||
clangDecl->getLocation(), /*ListInitialization*/ false);
|
||||
if (!constructExprResult.isUsable())
|
||||
return;
|
||||
|
||||
auto castExpr = dyn_cast_or_null<clang::CastExpr>(constructExprResult.get());
|
||||
if (!castExpr)
|
||||
return;
|
||||
|
||||
auto bindTempExpr =
|
||||
dyn_cast_or_null<clang::CXXBindTemporaryExpr>(castExpr->getSubExpr());
|
||||
if (!bindTempExpr)
|
||||
return;
|
||||
|
||||
auto constructExpr =
|
||||
dyn_cast_or_null<clang::CXXConstructExpr>(bindTempExpr->getSubExpr());
|
||||
if (!constructExpr)
|
||||
return;
|
||||
|
||||
auto constructorDecl = constructExpr->getConstructor();
|
||||
|
||||
auto importedConstructor =
|
||||
impl.importDecl(constructorDecl, impl.CurrentVersion);
|
||||
if (!importedConstructor)
|
||||
return;
|
||||
decl->addMember(importedConstructor);
|
||||
|
||||
// TODO: actually conform to some form of CxxFunction protocol
|
||||
|
||||
}
|
||||
|
||||
void swift::conformToCxxSpanIfNeeded(ClangImporter::Implementation &impl,
|
||||
NominalTypeDecl *decl,
|
||||
const clang::CXXRecordDecl *clangDecl) {
|
||||
|
||||
@@ -71,12 +71,6 @@ void conformToCxxVectorIfNeeded(ClangImporter::Implementation &impl,
|
||||
NominalTypeDecl *decl,
|
||||
const clang::CXXRecordDecl *clangDecl);
|
||||
|
||||
/// If the decl is an instantiation of C++ `std::function`, synthesize a
|
||||
/// conformance to CxxFunction, which is defined in the Cxx module.
|
||||
void conformToCxxFunctionIfNeeded(ClangImporter::Implementation &impl,
|
||||
NominalTypeDecl *decl,
|
||||
const clang::CXXRecordDecl *clangDecl);
|
||||
|
||||
/// If the decl is an instantiation of C++ `std::span`, synthesize a
|
||||
/// conformance to CxxSpan, which is defined in the Cxx module.
|
||||
void conformToCxxSpanIfNeeded(ClangImporter::Implementation &impl,
|
||||
|
||||
@@ -7929,6 +7929,65 @@ ClangImporter::getDefaultArgGenerator(const clang::ParmVarDecl *param) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool ClangImporter::needsClosureConstructor(
|
||||
const clang::CXXRecordDecl *recordDecl) const {
|
||||
return Impl.needsClosureConstructor(recordDecl);
|
||||
}
|
||||
|
||||
bool ClangImporter::Implementation::needsClosureConstructor(
|
||||
const clang::CXXRecordDecl *recordDecl) const {
|
||||
// In the future, this should probably be configurable via a Clang attribute.
|
||||
return recordDecl->isInStdNamespace() && recordDecl->getIdentifier() &&
|
||||
recordDecl->getName() == "function";
|
||||
}
|
||||
|
||||
bool ClangImporter::isSwiftFunctionWrapper(
|
||||
const clang::RecordDecl *decl) const {
|
||||
return Impl.isSwiftFunctionWrapper(decl);
|
||||
}
|
||||
|
||||
bool ClangImporter::Implementation::isSwiftFunctionWrapper(
|
||||
const clang::RecordDecl *decl) const {
|
||||
return decl->getIdentifier() && decl->getName() == "__SwiftFunctionWrapper";
|
||||
}
|
||||
|
||||
bool ClangImporter::isDeconstructedSwiftClosure(const clang::Type *type) const {
|
||||
auto recordDecl = type->getAsCXXRecordDecl();
|
||||
return recordDecl && recordDecl->getIdentifier() &&
|
||||
recordDecl->getName() == "__swift_interop_closure";
|
||||
}
|
||||
|
||||
const clang::FunctionType *ClangImporter::extractCXXFunctionType(
|
||||
const clang::CXXRecordDecl *functionalTypeDecl) const {
|
||||
auto &clangCtx = functionalTypeDecl->getASTContext();
|
||||
auto operatorCallName = clangCtx.DeclarationNames.getCXXOperatorName(
|
||||
clang::OverloadedOperatorKind::OO_Call);
|
||||
auto lookupResult = functionalTypeDecl->lookup(operatorCallName);
|
||||
const clang::CXXMethodDecl *operatorCall = nullptr;
|
||||
// If an overload of operator() was found, assert that it's a single one.
|
||||
if (!lookupResult.empty()) {
|
||||
ASSERT(lookupResult.isSingleResult() &&
|
||||
"expected single operator() in a functional type");
|
||||
operatorCall = cast<clang::CXXMethodDecl>(lookupResult.front());
|
||||
} else {
|
||||
// If no overload if operator() was found, there could be a viable overload
|
||||
// in one of the base types. For instance, std::function in Microsoft STL
|
||||
// exposes an operator() from a base type.
|
||||
functionalTypeDecl->forallBases([&](const clang::CXXRecordDecl *base) {
|
||||
auto baseResult = base->lookup(operatorCallName);
|
||||
if (!baseResult.empty()) {
|
||||
ASSERT(!operatorCall && "expected single operator() across base types");
|
||||
ASSERT(baseResult.isSingleResult() &&
|
||||
"expected single operator() in a base type");
|
||||
operatorCall = cast<clang::CXXMethodDecl>(baseResult.front());
|
||||
}
|
||||
return true;
|
||||
});
|
||||
ASSERT(operatorCall && "expected operator() in one of the bases");
|
||||
}
|
||||
return operatorCall->getType()->getAs<clang::FunctionType>();
|
||||
}
|
||||
|
||||
FuncDecl *
|
||||
ClangImporter::getAvailabilityDomainPredicate(const clang::VarDecl *var) {
|
||||
auto it = Impl.availabilityDomainPredicates.find(var);
|
||||
|
||||
@@ -2625,6 +2625,12 @@ namespace {
|
||||
cxxRecordDecl->getName() == "pair") {
|
||||
forceMemberwiseInitializer = true;
|
||||
}
|
||||
// If this is the type that wraps around a Swift closure for the purpose
|
||||
// of std::function support, force a memberwise initializer. It will be
|
||||
// called by the synthesized std::function initializer.
|
||||
if (cxxRecordDecl && Impl.isSwiftFunctionWrapper(cxxRecordDecl))
|
||||
forceMemberwiseInitializer = true;
|
||||
|
||||
// We can assume that it is possible to correctly construct the object by
|
||||
// simply initializing its member variables to arbitrary supplied values
|
||||
// only when the same is possible in C++. While we could check for that
|
||||
@@ -3300,8 +3306,13 @@ namespace {
|
||||
conformToCxxPairIfNeeded(Impl, nominalDecl, decl);
|
||||
conformToCxxOptionalIfNeeded(Impl, nominalDecl, decl);
|
||||
conformToCxxVectorIfNeeded(Impl, nominalDecl, decl);
|
||||
conformToCxxFunctionIfNeeded(Impl, nominalDecl, decl);
|
||||
conformToCxxSpanIfNeeded(Impl, nominalDecl, decl);
|
||||
|
||||
if (Impl.needsClosureConstructor(decl)) {
|
||||
if (auto closureCtor =
|
||||
synthesizer.makeClosureConstructor(nominalDecl))
|
||||
nominalDecl->addMember(closureCtor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4612,6 +4623,29 @@ namespace {
|
||||
auto fieldType = desugarIfElaborated(decl->getType());
|
||||
ImportedType importedType = importer::findOptionSetEnum(fieldType, Impl);
|
||||
|
||||
// If this is a closure field of the __SwiftFunctionWrapper type, pretend
|
||||
// that the type of the field is a Swift closure. The actual Clang type is
|
||||
// a pair of two pointers: code and context.
|
||||
if (!importedType && decl->getParent() &&
|
||||
decl->getParent()->getIdentifier() &&
|
||||
Impl.isSwiftFunctionWrapper(decl->getParent()) &&
|
||||
name.is("closure")) {
|
||||
auto &ctx = dc->getASTContext();
|
||||
auto functionWrapperDecl = dc->getSelfStructDecl();
|
||||
auto callAsFunctionOverloads =
|
||||
functionWrapperDecl->lookupDirect(ctx.Id_callAsFunction);
|
||||
ASSERT(callAsFunctionOverloads.size() == 1 &&
|
||||
"__SwiftFunctionWrapper should only have one operator()");
|
||||
auto callAsFunctionDecl =
|
||||
cast<FuncDecl>(callAsFunctionOverloads.front());
|
||||
|
||||
auto closureType = callAsFunctionDecl->getInterfaceType()
|
||||
->getAs<FunctionType>()
|
||||
->getResult();
|
||||
|
||||
importedType = ImportedType(closureType, false);
|
||||
}
|
||||
|
||||
if (!importedType)
|
||||
importedType =
|
||||
Impl.importType(decl->getType(), ImportTypeKind::RecordField,
|
||||
|
||||
@@ -706,6 +706,10 @@ public:
|
||||
|
||||
bool isDefaultArgSafeToImport(const clang::ParmVarDecl *param);
|
||||
|
||||
bool needsClosureConstructor(const clang::CXXRecordDecl *recordDecl) const;
|
||||
|
||||
bool isSwiftFunctionWrapper(const clang::RecordDecl *decl) const;
|
||||
|
||||
ValueDecl *importBaseMemberDecl(ValueDecl *decl, DeclContext *newContext,
|
||||
ClangInheritanceInfo inheritance);
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "swift/AST/Expr.h"
|
||||
#include "swift/AST/ParameterList.h"
|
||||
#include "swift/AST/Pattern.h"
|
||||
#include "swift/AST/PrettyStackTrace.h"
|
||||
#include "swift/AST/Stmt.h"
|
||||
#include "swift/AST/TypeCheckRequests.h"
|
||||
#include "swift/Basic/Assertions.h"
|
||||
@@ -78,7 +79,7 @@ static CallExpr *createAccessorImplCallExpr(FuncDecl *accessorImpl,
|
||||
return accessorImplCallExpr;
|
||||
}
|
||||
|
||||
static DeclRefExpr *createParamRefExpr(AccessorDecl *accessorDecl,
|
||||
static DeclRefExpr *createParamRefExpr(AbstractFunctionDecl *accessorDecl,
|
||||
unsigned index) {
|
||||
ASTContext &ctx = accessorDecl->getASTContext();
|
||||
|
||||
@@ -2814,6 +2815,253 @@ SwiftDeclSynthesizer::makeDefaultArgument(const clang::ParmVarDecl *param,
|
||||
return callExpr;
|
||||
}
|
||||
|
||||
// MARK: C++ functional type constructors
|
||||
|
||||
/// Synthesizer callback for the constructor that takes a Swift closure.
|
||||
///
|
||||
/// \code
|
||||
/// struct function<(Args...) -> ReturnType> { // imported from C++
|
||||
/// init(_ closure: (Args...) -> ReturnType) { // synthesized here
|
||||
/// self.init(__SwiftFunctionWrapper<...>(closure: closure)))
|
||||
/// }
|
||||
/// }
|
||||
/// \endcode
|
||||
static std::pair<BraceStmt *, bool>
|
||||
synthesizeFunctionConstructorBody(AbstractFunctionDecl *afd, void *context) {
|
||||
auto constructor = cast<ConstructorDecl>(afd);
|
||||
auto functionTypeDecl = cast<StructDecl>(constructor->getParent());
|
||||
auto functionTypeClangDecl =
|
||||
cast<clang::CXXRecordDecl>(functionTypeDecl->getClangDecl());
|
||||
auto callAsFunctionDecl = static_cast<FuncDecl *>(context);
|
||||
|
||||
ASTContext &ctx = constructor->getASTContext();
|
||||
clang::ASTContext &clangCtx = functionTypeClangDecl->getASTContext();
|
||||
auto clangImporter = ctx.getClangModuleLoader();
|
||||
auto &clangSema = clangImporter->getClangSema();
|
||||
|
||||
// operator() might be declared on a base type of the functional type.
|
||||
auto callAsFunctionBase =
|
||||
clangImporter->getOriginalForClonedMember(callAsFunctionDecl);
|
||||
auto operatorCallDecl =
|
||||
callAsFunctionBase
|
||||
? cast<clang::CXXMethodDecl>(callAsFunctionBase->getClangDecl())
|
||||
: cast<clang::CXXMethodDecl>(callAsFunctionDecl->getClangDecl());
|
||||
|
||||
auto desugarIfTemplateSubst = [](clang::QualType type) {
|
||||
if (auto sugared = dyn_cast<clang::SubstTemplateTypeParmType>(type))
|
||||
return sugared->desugar();
|
||||
return type;
|
||||
};
|
||||
|
||||
SmallVector<clang::TemplateArgument, 2> operatorCallParamTypes;
|
||||
llvm::transform(operatorCallDecl->parameters(),
|
||||
std::back_inserter(operatorCallParamTypes),
|
||||
[&](const clang::ParmVarDecl *paramDecl) {
|
||||
return desugarIfTemplateSubst(paramDecl->getType());
|
||||
});
|
||||
|
||||
auto closureParamRefExr = createParamRefExpr(constructor, 0);
|
||||
|
||||
auto cxxStdlibShimModule =
|
||||
ctx.getLoadedModule(ctx.getIdentifier(CXX_STDLIB_SHIM_NAME));
|
||||
SmallVector<ValueDecl *, 1> cxxStdlibShimLookupResults;
|
||||
ctx.lookupInModule(cxxStdlibShimModule, "__SwiftFunctionWrapper",
|
||||
cxxStdlibShimLookupResults);
|
||||
ASSERT(cxxStdlibShimLookupResults.size() == 1 &&
|
||||
"Must be one exactly __SwiftFunctionWrapper");
|
||||
auto functionWrapperTemplate = cast<clang::ClassTemplateDecl>(
|
||||
cxxStdlibShimLookupResults.front()->getClangDecl());
|
||||
|
||||
auto functionReturnType =
|
||||
desugarIfTemplateSubst(operatorCallDecl->getReturnType());
|
||||
auto functionType = operatorCallDecl->getType()->getAs<clang::FunctionType>();
|
||||
|
||||
auto closureType = callAsFunctionDecl->getInterfaceType()
|
||||
->getAs<FunctionType>()
|
||||
->getResult()
|
||||
->getAs<FunctionType>();
|
||||
// Make sure we honor the C++ function type that corresponds to the closure
|
||||
// type when computing the pointer authentication discriminator. This is
|
||||
// important in cases where Swift needs to reabstract the closure, e.g. if one
|
||||
// of the parameters has a type which is conventionally passed directly in
|
||||
// C++, but indirectly in Swift, which would require a Swift thunk. In that
|
||||
// case, we need the discriminator for the thunk here, not for the original
|
||||
// closure type.
|
||||
auto ptrAuthDiscriminator =
|
||||
closureType->getPointerAuthDiscriminator(*ctx.MainModule, functionType);
|
||||
|
||||
std::array<clang::TemplateArgument, 3> functionWrapperTemplateArgs = {
|
||||
clang::TemplateArgument(
|
||||
clangCtx,
|
||||
llvm::APSInt(APInt(clangCtx.getIntWidth(clangCtx.UnsignedIntTy),
|
||||
ptrAuthDiscriminator)),
|
||||
clangCtx.UnsignedIntTy),
|
||||
clang::TemplateArgument(functionReturnType),
|
||||
clang::TemplateArgument::CreatePackCopy(clangCtx,
|
||||
operatorCallParamTypes)};
|
||||
|
||||
// Instantiate __SwiftFunctionWrapper<...> for the closure.
|
||||
auto wrapperInstDecl = clangImporter->instantiateCXXClassTemplate(
|
||||
const_cast<clang::ClassTemplateDecl *>(functionWrapperTemplate),
|
||||
functionWrapperTemplateArgs);
|
||||
ASSERT(wrapperInstDecl && "expected __SwiftFunctionWrapper instantiation");
|
||||
|
||||
auto wrapperClangDecl =
|
||||
cast<clang::CXXRecordDecl>(wrapperInstDecl->getClangDecl());
|
||||
auto wrapperClangType = clangCtx.getRecordType(wrapperClangDecl).withConst();
|
||||
|
||||
// Create a fake variable with the __SwiftFunctionWrapper<...> type.
|
||||
auto fakeWrapperVarDecl = clang::VarDecl::Create(
|
||||
clangCtx, /*DC*/ clangCtx.getTranslationUnitDecl(),
|
||||
clang::SourceLocation(), clang::SourceLocation(), /*Id*/ nullptr,
|
||||
wrapperClangType, clangCtx.getTrivialTypeSourceInfo(wrapperClangType),
|
||||
clang::StorageClass::SC_None);
|
||||
auto fakeWrapperRefExpr = new (clangCtx) clang::DeclRefExpr(
|
||||
clangCtx, fakeWrapperVarDecl, false, wrapperClangType,
|
||||
clang::ExprValueKind::VK_LValue, clang::SourceLocation());
|
||||
|
||||
auto functionTypeClangType = clangCtx.getRecordType(functionTypeClangDecl);
|
||||
auto functionTypeClangInfo =
|
||||
clangCtx.getTrivialTypeSourceInfo(functionTypeClangType);
|
||||
SmallVector<clang::Expr *, 1> constructExprArgs = {fakeWrapperRefExpr};
|
||||
|
||||
// Instantiate the templated constructor that would accept the fake
|
||||
// __SwiftFunctionWrapper<...> variable.
|
||||
auto constructExprResult = clangSema.BuildCXXTypeConstructExpr(
|
||||
functionTypeClangInfo, functionTypeClangDecl->getLocation(),
|
||||
constructExprArgs, functionTypeClangDecl->getLocation(),
|
||||
/*ListInitialization*/ false);
|
||||
ASSERT(constructExprResult.isUsable() && "constructor expression expected");
|
||||
|
||||
// Unwrap the instantiated C++ constructor.
|
||||
auto castExpr = cast<clang::CastExpr>(constructExprResult.get());
|
||||
auto bindTempExpr = cast<clang::CXXBindTemporaryExpr>(castExpr->getSubExpr());
|
||||
auto constructExpr =
|
||||
cast<clang::CXXConstructExpr>(bindTempExpr->getSubExpr());
|
||||
auto constructorDecl = constructExpr->getConstructor();
|
||||
|
||||
// Import the constructor: std.function<...>(_: __SwiftFunctionWrapper<...>).
|
||||
// It will be called from the synthesized Swift AST below.
|
||||
auto functionTypeCtor =
|
||||
cast<ConstructorDecl>(clangImporter->importDeclDirectly(constructorDecl));
|
||||
functionTypeDecl->addMember(functionTypeCtor);
|
||||
|
||||
// Find the constructor:
|
||||
// __SwiftFunctionWrapper<...>(closure: (Args...) -> ReturnType).
|
||||
auto wrapperInstCtorIt =
|
||||
llvm::find_if(wrapperInstDecl->getMembers(), [&](Decl *member) -> bool {
|
||||
if (auto wrapperCtor = dyn_cast<ConstructorDecl>(member)) {
|
||||
return wrapperCtor->isMemberwiseInitializer();
|
||||
}
|
||||
return false;
|
||||
});
|
||||
ASSERT(wrapperInstCtorIt != wrapperInstDecl->getMembers().end() &&
|
||||
"expected a constructor of __SwiftFunctionWrapper");
|
||||
auto wrapperInstCtor = cast<ConstructorDecl>(*wrapperInstCtorIt);
|
||||
|
||||
auto wrapperInstCtorRefExpr =
|
||||
new (ctx) DeclRefExpr(wrapperInstCtor, DeclNameLoc(), /*Implicit*/ true);
|
||||
wrapperInstCtorRefExpr->setType(wrapperInstCtor->getInterfaceType());
|
||||
wrapperInstCtorRefExpr->setFunctionRefInfo(
|
||||
FunctionRefInfo::singleBaseNameApply());
|
||||
|
||||
auto wrapperInstTypeExpr = TypeExpr::createImplicitForDecl(
|
||||
DeclNameLoc(), wrapperInstDecl, constructor,
|
||||
constructor->mapTypeIntoEnvironment(wrapperInstDecl->getInterfaceType()));
|
||||
auto wrapperInstInitExpr = ConstructorRefCallExpr::create(
|
||||
ctx, wrapperInstCtorRefExpr, wrapperInstTypeExpr,
|
||||
wrapperInstCtor->getMethodInterfaceType());
|
||||
wrapperInstInitExpr->setThrows(nullptr);
|
||||
|
||||
// Call the constructor:
|
||||
// __SwiftFunctionWrapper<...>(closure: closure)
|
||||
auto wrapperInstInitCallExpr = CallExpr::createImplicit(
|
||||
ctx, wrapperInstInitExpr,
|
||||
ArgumentList::createImplicit(
|
||||
ctx, {Argument(SourceLoc(), ctx.getIdentifier("closure"),
|
||||
closureParamRefExr)}));
|
||||
wrapperInstInitCallExpr->setType(wrapperInstCtor->getResultInterfaceType());
|
||||
wrapperInstInitCallExpr->setThrows(nullptr);
|
||||
|
||||
auto functionTypeCtorRefExpr =
|
||||
new (ctx) DeclRefExpr(functionTypeCtor, DeclNameLoc(), /*Implicit*/ true);
|
||||
functionTypeCtorRefExpr->setType(functionTypeCtor->getInterfaceType());
|
||||
functionTypeCtorRefExpr->setFunctionRefInfo(
|
||||
FunctionRefInfo::singleBaseNameApply());
|
||||
|
||||
auto underlyingFunctionCtorRefExpr = new (ctx) OtherConstructorDeclRefExpr(
|
||||
ConcreteDeclRef(functionTypeCtor), DeclNameLoc(), /*Implicit*/ true,
|
||||
functionTypeCtor->getInitializerInterfaceType());
|
||||
|
||||
auto inoutSelfDecl = constructor->getImplicitSelfDecl();
|
||||
auto inoutSelfRef = new (ctx) DeclRefExpr(inoutSelfDecl, DeclNameLoc(),
|
||||
/*implicit*/ true);
|
||||
inoutSelfRef->setType(LValueType::get(inoutSelfDecl->getInterfaceType()));
|
||||
|
||||
auto underlyingFunctionCtorCallExpr =
|
||||
DotSyntaxCallExpr::create(ctx, underlyingFunctionCtorRefExpr, SourceLoc(),
|
||||
Argument::implicitInOut(ctx, inoutSelfRef));
|
||||
underlyingFunctionCtorCallExpr->setType(
|
||||
functionTypeCtor->getMethodInterfaceType());
|
||||
underlyingFunctionCtorCallExpr->setThrows(nullptr);
|
||||
|
||||
// Finally, call the std.function constructor.
|
||||
auto functionTypeInitCallExpr = CallExpr::createImplicit(
|
||||
ctx, underlyingFunctionCtorCallExpr,
|
||||
ArgumentList::createImplicit(
|
||||
ctx, {Argument(SourceLoc(), Identifier(), wrapperInstInitCallExpr)}));
|
||||
functionTypeInitCallExpr->setType(functionTypeCtor->getResultInterfaceType());
|
||||
functionTypeInitCallExpr->setThrows(nullptr);
|
||||
|
||||
auto rebindSelfExpr = new (ctx)
|
||||
RebindSelfInConstructorExpr(functionTypeInitCallExpr, inoutSelfDecl);
|
||||
rebindSelfExpr->setImplicit();
|
||||
|
||||
auto returnStmt = ReturnStmt::createImplicit(ctx, /*expr*/ nullptr);
|
||||
|
||||
// Create the function body.
|
||||
auto body = BraceStmt::create(ctx, SourceLoc(), {rebindSelfExpr, returnStmt},
|
||||
SourceLoc());
|
||||
return {body, /*isTypeChecked=*/true};
|
||||
}
|
||||
|
||||
ConstructorDecl *SwiftDeclSynthesizer::makeClosureConstructor(NominalTypeDecl *decl) {
|
||||
PrettyStackTraceDecl trace("creating a closure constructor", decl);
|
||||
assert(decl);
|
||||
ASTContext &ctx = decl->getASTContext();
|
||||
|
||||
auto callAsFunctionOverloads = decl->lookupDirect(ctx.Id_callAsFunction);
|
||||
if (callAsFunctionOverloads.size() != 1)
|
||||
return nullptr;
|
||||
auto callAsFunctionDecl = cast<FuncDecl>(callAsFunctionOverloads.front());
|
||||
|
||||
auto closureType = callAsFunctionDecl->getInterfaceType()
|
||||
->getAs<FunctionType>()
|
||||
->getResult();
|
||||
|
||||
auto closureParam = new (ctx) ParamDecl(
|
||||
/*specifierLoc*/ SourceLoc(), /*argumentNameLoc*/ SourceLoc(),
|
||||
/*argumentName*/ Identifier(), /*parameterNameLoc*/ SourceLoc(),
|
||||
/*parameterName*/ ctx.getIdentifier("closure"), /*declContext*/ decl);
|
||||
closureParam->setInterfaceType(closureType);
|
||||
closureParam->setSpecifier(ParamSpecifier::Default);
|
||||
auto paramList = ParameterList::create(ctx, {closureParam});
|
||||
|
||||
DeclName constructorDeclName(ctx, DeclBaseName::createConstructor(),
|
||||
paramList);
|
||||
auto constructorDecl = new (ctx) ConstructorDecl(
|
||||
constructorDeclName, SourceLoc(),
|
||||
/*Failable*/ false, /*FailabilityLoc*/ SourceLoc(),
|
||||
/*Async*/ false, /*AsyncLoc*/ SourceLoc(),
|
||||
/*Throws*/ false, /*ThrowsLoc*/ SourceLoc(),
|
||||
/*ThrownType*/ TypeLoc(), paramList, /*GenericParams*/ nullptr, decl);
|
||||
constructorDecl->setAccess(AccessLevel::Public);
|
||||
constructorDecl->setSynthesized();
|
||||
constructorDecl->setBodySynthesizer(synthesizeFunctionConstructorBody,
|
||||
callAsFunctionDecl);
|
||||
return constructorDecl;
|
||||
}
|
||||
|
||||
// MARK: C++ foreign reference type constructors
|
||||
|
||||
llvm::SmallVector<clang::CXXMethodDecl *, 4>
|
||||
|
||||
@@ -339,6 +339,10 @@ public:
|
||||
const swift::Type &swiftParamTy,
|
||||
SourceLoc paramLoc);
|
||||
|
||||
/// Synthesizes a constructor for a functional type imported from C++, which
|
||||
/// takes a Swift closure as a single parameter.
|
||||
ConstructorDecl *makeClosureConstructor(NominalTypeDecl *decl);
|
||||
|
||||
/// Synthesize a static factory method for a C++ foreign reference type,
|
||||
/// returning a `CXXMethodDecl*` or `nullptr` if the required constructor or
|
||||
/// allocation function is not found.
|
||||
|
||||
@@ -478,163 +478,16 @@ PointerAuthEntity::getDeclDiscriminator(IRGenModule &IGM) const {
|
||||
llvm_unreachable("bad kind");
|
||||
}
|
||||
|
||||
static void hashStringForFunctionType(IRGenModule &IGM, CanSILFunctionType type,
|
||||
raw_ostream &Out,
|
||||
GenericEnvironment *genericEnv);
|
||||
|
||||
static void hashStringForType(IRGenModule &IGM, CanType Ty, raw_ostream &Out,
|
||||
GenericEnvironment *genericEnv) {
|
||||
if (Ty->isAnyClassReferenceType()) {
|
||||
// Any class type has to be hashed opaquely.
|
||||
Out << "-class";
|
||||
} else if (isa<AnyMetatypeType>(Ty)) {
|
||||
// Any metatype has to be hashed opaquely.
|
||||
Out << "-metatype";
|
||||
} else if (auto UnwrappedTy = Ty->getOptionalObjectType()) {
|
||||
if (UnwrappedTy->isBridgeableObjectType()) {
|
||||
// Optional<T> is compatible with T when T is class-based.
|
||||
hashStringForType(IGM, UnwrappedTy->getCanonicalType(), Out, genericEnv);
|
||||
} else if (UnwrappedTy->is<MetatypeType>()) {
|
||||
// Optional<T> is compatible with T when T is a metatype.
|
||||
hashStringForType(IGM, UnwrappedTy->getCanonicalType(), Out, genericEnv);
|
||||
} else {
|
||||
// Optional<T> is direct if and only if T is.
|
||||
Out << "Optional<";
|
||||
hashStringForType(IGM, UnwrappedTy->getCanonicalType(), Out, genericEnv);
|
||||
Out << ">";
|
||||
}
|
||||
} else if (auto ETy = dyn_cast<ExistentialType>(Ty)) {
|
||||
// Look through existential types
|
||||
hashStringForType(IGM, ETy->getConstraintType()->getCanonicalType(),
|
||||
Out, genericEnv);
|
||||
} else if (auto GTy = dyn_cast<AnyGenericType>(Ty)) {
|
||||
// For generic and non-generic value types, use the mangled declaration
|
||||
// name, and ignore all generic arguments.
|
||||
NominalTypeDecl *nominal = cast<NominalTypeDecl>(GTy->getDecl());
|
||||
Out << Mangle::ASTMangler(IGM.Context).mangleNominalType(nominal);
|
||||
} else if (auto FTy = dyn_cast<SILFunctionType>(Ty)) {
|
||||
Out << "(";
|
||||
hashStringForFunctionType(IGM, FTy, Out, genericEnv);
|
||||
Out << ")";
|
||||
} else {
|
||||
Out << "-";
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static void hashStringForList(IRGenModule &IGM, const ArrayRef<T> &list,
|
||||
raw_ostream &Out, GenericEnvironment *genericEnv,
|
||||
const SILFunctionType *fnType) {
|
||||
for (auto paramOrRetVal : list) {
|
||||
if (paramOrRetVal.isFormalIndirect()) {
|
||||
// Indirect params and return values have to be opaque.
|
||||
Out << "-indirect";
|
||||
} else {
|
||||
CanType Ty = paramOrRetVal.getArgumentType(
|
||||
IGM.getSILModule(), fnType, IGM.getMaximalTypeExpansionContext());
|
||||
if (Ty->hasTypeParameter())
|
||||
Ty = genericEnv->mapTypeIntoEnvironment(Ty)->getCanonicalType();
|
||||
hashStringForType(IGM, Ty, Out, genericEnv);
|
||||
}
|
||||
Out << ":";
|
||||
}
|
||||
}
|
||||
|
||||
static void hashStringForList(IRGenModule &IGM,
|
||||
const ArrayRef<SILResultInfo> &list,
|
||||
raw_ostream &Out, GenericEnvironment *genericEnv,
|
||||
const SILFunctionType *fnType) {
|
||||
for (auto paramOrRetVal : list) {
|
||||
if (paramOrRetVal.isFormalIndirect()) {
|
||||
// Indirect params and return values have to be opaque.
|
||||
Out << "-indirect";
|
||||
} else {
|
||||
CanType Ty = paramOrRetVal.getReturnValueType(
|
||||
IGM.getSILModule(), fnType, IGM.getMaximalTypeExpansionContext());
|
||||
if (Ty->hasTypeParameter())
|
||||
Ty = genericEnv->mapTypeIntoEnvironment(Ty)->getCanonicalType();
|
||||
hashStringForType(IGM, Ty, Out, genericEnv);
|
||||
}
|
||||
Out << ":";
|
||||
}
|
||||
}
|
||||
|
||||
static void hashStringForFunctionType(IRGenModule &IGM, CanSILFunctionType type,
|
||||
raw_ostream &Out,
|
||||
GenericEnvironment *genericEnv) {
|
||||
Out << (type->isCoroutine() ? "coroutine" : "function") << ":";
|
||||
Out << type->getNumParameters() << ":";
|
||||
hashStringForList(IGM, type->getParameters(), Out, genericEnv, type);
|
||||
Out << type->getNumResults() << ":";
|
||||
hashStringForList(IGM, type->getResults(), Out, genericEnv, type);
|
||||
if (type->isCoroutine()) {
|
||||
Out << type->getNumYields() << ":";
|
||||
hashStringForList(IGM, type->getYields(), Out, genericEnv, type);
|
||||
}
|
||||
}
|
||||
|
||||
static llvm::ConstantInt *getTypeDiscriminator(IRGenModule &IGM,
|
||||
CanSILFunctionType type) {
|
||||
// The hash we need to do here ignores:
|
||||
// - thickness, so that we can promote thin-to-thick without rehashing;
|
||||
// - error results, so that we can promote nonthrowing-to-throwing
|
||||
// without rehashing;
|
||||
// - isolation, so that global actor annotations can change in the SDK
|
||||
// without breaking compatibility and so that we can erase it to
|
||||
// nonisolated without rehashing;
|
||||
// - types of indirect arguments/retvals, so they can be substituted freely;
|
||||
// - types of class arguments/retvals
|
||||
// - types of metatype arguments/retvals
|
||||
// See isABICompatibleWith and areABICompatibleParamsOrReturns in
|
||||
// SILFunctionType.cpp.
|
||||
|
||||
SmallString<32> Buffer;
|
||||
llvm::raw_svector_ostream Out(Buffer);
|
||||
auto genericSig = type->getInvocationGenericSignature();
|
||||
hashStringForFunctionType(
|
||||
IGM, type, Out,
|
||||
genericSig.getCanonicalSignature().getGenericEnvironment());
|
||||
return getDiscriminatorForString(IGM, Out.str());
|
||||
return llvm::ConstantInt::get(
|
||||
IGM.Int64Ty, type->getPointerAuthDiscriminator(&IGM.getSILModule()));
|
||||
}
|
||||
|
||||
static llvm::ConstantInt *
|
||||
getCoroutineYieldTypesDiscriminator(IRGenModule &IGM, CanSILFunctionType type) {
|
||||
SmallString<32> buffer;
|
||||
llvm::raw_svector_ostream out(buffer);
|
||||
auto genericSig = type->getInvocationGenericSignature();
|
||||
auto *genericEnv = genericSig.getCanonicalSignature().getGenericEnvironment();
|
||||
|
||||
out << [&]() -> StringRef {
|
||||
switch (type->getCoroutineKind()) {
|
||||
case SILCoroutineKind::YieldMany: return "yield_many:";
|
||||
case SILCoroutineKind::YieldOnce: return "yield_once:";
|
||||
case SILCoroutineKind::YieldOnce2:
|
||||
return "yield_once_2:";
|
||||
case SILCoroutineKind::None: llvm_unreachable("not a coroutine");
|
||||
}
|
||||
llvm_unreachable("bad coroutine kind");
|
||||
}();
|
||||
|
||||
out << type->getNumYields() << ":";
|
||||
|
||||
for (auto yield: type->getYields()) {
|
||||
// We can't mangle types on inout and indirect yields because they're
|
||||
// abstractable.
|
||||
if (yield.isIndirectInOut()) {
|
||||
out << "inout";
|
||||
} else if (yield.isFormalIndirect()) {
|
||||
out << "indirect";
|
||||
} else {
|
||||
CanType Ty = yield.getArgumentType(IGM.getSILModule(), type,
|
||||
IGM.getMaximalTypeExpansionContext());
|
||||
if (Ty->hasTypeParameter())
|
||||
Ty = genericEnv->mapTypeIntoEnvironment(Ty)->getCanonicalType();
|
||||
hashStringForType(IGM, Ty, out, genericEnv);
|
||||
}
|
||||
out << ":";
|
||||
}
|
||||
|
||||
return getDiscriminatorForString(IGM, out.str());
|
||||
return llvm::ConstantInt::get(
|
||||
IGM.Int64Ty, type->getCoroutineYieldTypesDiscriminator(IGM.getSILModule()));
|
||||
}
|
||||
|
||||
llvm::ConstantInt *
|
||||
|
||||
@@ -2372,8 +2372,7 @@ const llvm::StringRef IRGenerator::getClangDataLayoutString() {
|
||||
}
|
||||
|
||||
TypeExpansionContext IRGenModule::getMaximalTypeExpansionContext() const {
|
||||
return TypeExpansionContext::maximal(getSILModule().getAssociatedContext(),
|
||||
getSILModule().isWholeModule());
|
||||
return getSILModule().getMaximalTypeExpansionContext();
|
||||
}
|
||||
|
||||
const TypeLayoutEntry
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#define DEBUG_TYPE "libsil"
|
||||
#include "swift/AST/ASTContext.h"
|
||||
#include "swift/AST/ClangModuleLoader.h"
|
||||
#include "swift/AST/ConformanceLookup.h"
|
||||
#include "swift/AST/Decl.h"
|
||||
#include "swift/AST/ForeignAsyncConvention.h"
|
||||
@@ -98,6 +99,21 @@ TypeConverter::getAbstractionPattern(VarDecl *var, bool isNonObjC) {
|
||||
if (auto clangDecl = var->getClangDecl()) {
|
||||
auto clangType = getClangType(clangDecl);
|
||||
auto contextType = var->getDeclContext()->mapTypeIntoEnvironment(swiftType);
|
||||
|
||||
// If this is a Swift closure that is being deconstructed into an instance
|
||||
// of __swift_interop_closure, which stores a pair of two pointers, extract
|
||||
// the Clang type from the C++ functional type. This is used to support
|
||||
// interop between std::function and Swift closures. This kind of assignment
|
||||
// will only exist in compiler-generated code.
|
||||
auto clangImporter = var->getASTContext().getClangModuleLoader();
|
||||
if (clangImporter->isDeconstructedSwiftClosure(clangType)) {
|
||||
auto functionWrapperDecl = cast<clang::CXXRecordDecl>(
|
||||
var->getDeclContext()->getAsDecl()->getClangDecl());
|
||||
auto clangFunctionType =
|
||||
clangImporter->extractCXXFunctionType(functionWrapperDecl);
|
||||
return AbstractionPattern(sig, swiftType, clangFunctionType);
|
||||
}
|
||||
|
||||
swiftType =
|
||||
getLoweredBridgedType(AbstractionPattern(sig, swiftType, clangType),
|
||||
contextType, getClangDeclBridgeability(clangDecl),
|
||||
@@ -180,6 +196,25 @@ AbstractionPattern::getCurriedCXXMethod(CanType origType,
|
||||
return getCurriedCXXMethod(origType, clangMethod, function->getImportAsMemberStatus());
|
||||
}
|
||||
|
||||
AbstractionPattern AbstractionPattern::getCXXFunctionalConstructor(
|
||||
CanType origType, const clang::CXXRecordDecl *functionalTypeDecl) {
|
||||
auto &ctx = origType->getASTContext();
|
||||
auto &clangCtx = functionalTypeDecl->getASTContext();
|
||||
auto clangImporter = ctx.getClangModuleLoader();
|
||||
auto clangFunctionType =
|
||||
clangImporter->extractCXXFunctionType(functionalTypeDecl);
|
||||
auto ctorClangType =
|
||||
clangCtx
|
||||
.getFunctionType(clangCtx.getRecordType(functionalTypeDecl),
|
||||
{clang::QualType(clangFunctionType, 0)},
|
||||
clang::FunctionProtoType::ExtProtoInfo())
|
||||
.getTypePtr();
|
||||
AbstractionPattern pattern;
|
||||
pattern.initClangType(SubstitutionMap(), CanGenericSignature(), origType,
|
||||
ctorClangType, Kind::CXXFunctionalConstructorType);
|
||||
return pattern;
|
||||
}
|
||||
|
||||
AbstractionPattern
|
||||
AbstractionPattern::getOptional(AbstractionPattern object) {
|
||||
switch (object.getKind()) {
|
||||
@@ -195,6 +230,7 @@ AbstractionPattern::getOptional(AbstractionPattern object) {
|
||||
case Kind::CXXMethodType:
|
||||
case Kind::CurriedCXXMethodType:
|
||||
case Kind::PartialCurriedCXXMethodType:
|
||||
case Kind::CXXFunctionalConstructorType:
|
||||
case Kind::OpaqueFunction:
|
||||
case Kind::OpaqueDerivativeFunction:
|
||||
case Kind::ObjCCompletionHandlerArgumentsType:
|
||||
@@ -358,6 +394,7 @@ bool AbstractionPattern::conformsToKnownProtocol(
|
||||
case Kind::CXXMethodType:
|
||||
case Kind::CurriedCXXMethodType:
|
||||
case Kind::PartialCurriedCXXMethodType:
|
||||
case Kind::CXXFunctionalConstructorType:
|
||||
case Kind::OpaqueFunction:
|
||||
case Kind::OpaqueDerivativeFunction:
|
||||
return true;
|
||||
@@ -388,6 +425,7 @@ bool AbstractionPattern::matchesTuple(CanType substType) const {
|
||||
case Kind::CXXMethodType:
|
||||
case Kind::CurriedCXXMethodType:
|
||||
case Kind::PartialCurriedCXXMethodType:
|
||||
case Kind::CXXFunctionalConstructorType:
|
||||
case Kind::OpaqueFunction:
|
||||
case Kind::OpaqueDerivativeFunction:
|
||||
return false;
|
||||
@@ -490,6 +528,7 @@ AbstractionPattern::getTupleElementType(unsigned index) const {
|
||||
case Kind::CXXMethodType:
|
||||
case Kind::CurriedCXXMethodType:
|
||||
case Kind::PartialCurriedCXXMethodType:
|
||||
case Kind::CXXFunctionalConstructorType:
|
||||
case Kind::OpaqueFunction:
|
||||
case Kind::OpaqueDerivativeFunction:
|
||||
llvm_unreachable("function types are not tuples");
|
||||
@@ -549,6 +588,7 @@ bool AbstractionPattern::doesTupleContainPackExpansionType() const {
|
||||
case Kind::CXXMethodType:
|
||||
case Kind::CurriedCXXMethodType:
|
||||
case Kind::PartialCurriedCXXMethodType:
|
||||
case Kind::CXXFunctionalConstructorType:
|
||||
case Kind::OpaqueFunction:
|
||||
case Kind::OpaqueDerivativeFunction:
|
||||
llvm_unreachable("pattern is not a tuple");
|
||||
@@ -729,6 +769,7 @@ AbstractionPattern::getPackElementPackType() const {
|
||||
case Kind::CXXMethodType:
|
||||
case Kind::CurriedCXXMethodType:
|
||||
case Kind::PartialCurriedCXXMethodType:
|
||||
case Kind::CXXFunctionalConstructorType:
|
||||
case Kind::OpaqueFunction:
|
||||
case Kind::OpaqueDerivativeFunction:
|
||||
case Kind::ClangType:
|
||||
@@ -778,6 +819,7 @@ AbstractionPattern::getPackElementType(unsigned index) const {
|
||||
case Kind::CXXMethodType:
|
||||
case Kind::CurriedCXXMethodType:
|
||||
case Kind::PartialCurriedCXXMethodType:
|
||||
case Kind::CXXFunctionalConstructorType:
|
||||
case Kind::OpaqueFunction:
|
||||
case Kind::OpaqueDerivativeFunction:
|
||||
case Kind::ClangType:
|
||||
@@ -811,6 +853,7 @@ bool AbstractionPattern::matchesPack(CanPackType substType) const {
|
||||
case Kind::CXXMethodType:
|
||||
case Kind::CurriedCXXMethodType:
|
||||
case Kind::PartialCurriedCXXMethodType:
|
||||
case Kind::CXXFunctionalConstructorType:
|
||||
case Kind::OpaqueFunction:
|
||||
case Kind::OpaqueDerivativeFunction:
|
||||
case Kind::Tuple:
|
||||
@@ -926,6 +969,7 @@ AbstractionPattern AbstractionPattern::getPackExpansionPatternType() const {
|
||||
case Kind::CXXMethodType:
|
||||
case Kind::CurriedCXXMethodType:
|
||||
case Kind::PartialCurriedCXXMethodType:
|
||||
case Kind::CXXFunctionalConstructorType:
|
||||
case Kind::Tuple:
|
||||
case Kind::OpaqueFunction:
|
||||
case Kind::OpaqueDerivativeFunction:
|
||||
@@ -969,6 +1013,7 @@ AbstractionPattern AbstractionPattern::getPackExpansionCountType() const {
|
||||
case Kind::CXXMethodType:
|
||||
case Kind::CurriedCXXMethodType:
|
||||
case Kind::PartialCurriedCXXMethodType:
|
||||
case Kind::CXXFunctionalConstructorType:
|
||||
case Kind::Tuple:
|
||||
case Kind::OpaqueFunction:
|
||||
case Kind::OpaqueDerivativeFunction:
|
||||
@@ -1053,6 +1098,7 @@ AbstractionPattern AbstractionPattern::removingMoveOnlyWrapper() const {
|
||||
case Kind::CXXMethodType:
|
||||
case Kind::CurriedCXXMethodType:
|
||||
case Kind::PartialCurriedCXXMethodType:
|
||||
case Kind::CXXFunctionalConstructorType:
|
||||
case Kind::OpaqueFunction:
|
||||
case Kind::OpaqueDerivativeFunction:
|
||||
llvm_unreachable("function types can not be move only");
|
||||
@@ -1091,6 +1137,7 @@ AbstractionPattern AbstractionPattern::addingMoveOnlyWrapper() const {
|
||||
case Kind::CXXMethodType:
|
||||
case Kind::CurriedCXXMethodType:
|
||||
case Kind::PartialCurriedCXXMethodType:
|
||||
case Kind::CXXFunctionalConstructorType:
|
||||
case Kind::OpaqueFunction:
|
||||
case Kind::OpaqueDerivativeFunction:
|
||||
llvm_unreachable("function types can not be move only");
|
||||
@@ -1195,6 +1242,7 @@ AbstractionPattern AbstractionPattern::getFunctionResultType() const {
|
||||
case Kind::Discard:
|
||||
llvm_unreachable("don't need to discard function abstractions yet");
|
||||
case Kind::ClangType:
|
||||
case Kind::CXXFunctionalConstructorType:
|
||||
case Kind::CFunctionAsMethodType:
|
||||
case Kind::PartialCurriedCFunctionAsMethodType: {
|
||||
auto clangFunctionType = getClangFunctionType(getClangType());
|
||||
@@ -1342,6 +1390,7 @@ AbstractionPattern::getFunctionThrownErrorType() const {
|
||||
case Kind::PartialCurriedCFunctionAsMethodType:
|
||||
case Kind::CXXMethodType:
|
||||
case Kind::PartialCurriedCXXMethodType:
|
||||
case Kind::CXXFunctionalConstructorType:
|
||||
case Kind::CurriedObjCMethodType:
|
||||
case Kind::CurriedCFunctionAsMethodType:
|
||||
case Kind::CurriedCXXMethodType:
|
||||
@@ -1432,6 +1481,7 @@ AbstractionPattern::getObjCMethodAsyncCompletionHandlerType(
|
||||
case Kind::PartialCurriedCFunctionAsMethodType:
|
||||
case Kind::CXXMethodType:
|
||||
case Kind::PartialCurriedCXXMethodType:
|
||||
case Kind::CXXFunctionalConstructorType:
|
||||
case Kind::CurriedObjCMethodType:
|
||||
case Kind::CurriedCFunctionAsMethodType:
|
||||
case Kind::CurriedCXXMethodType:
|
||||
@@ -1636,6 +1686,18 @@ AbstractionPattern::getFunctionParamType(unsigned index) const {
|
||||
paramType,
|
||||
method->parameters()[paramIndex]->getType().getTypePtr());
|
||||
}
|
||||
case Kind::CXXFunctionalConstructorType:
|
||||
// If this is the last parameter of the Swift function type, it represents
|
||||
// Self. The Clang type will not have this parameter.
|
||||
if (index == getClangFunctionType(getClangType())
|
||||
->castAs<clang::FunctionProtoType>()
|
||||
->getNumParams()) {
|
||||
auto params = cast<AnyFunctionType>(getType()).getParams();
|
||||
return AbstractionPattern(getGenericSubstitutions(),
|
||||
getGenericSignatureForFunctionComponent(),
|
||||
params[index].getParameterType());
|
||||
}
|
||||
LLVM_FALLTHROUGH;
|
||||
case Kind::ClangType: {
|
||||
auto params = cast<AnyFunctionType>(getType()).getParams();
|
||||
return AbstractionPattern(getGenericSubstitutions(),
|
||||
@@ -1682,6 +1744,7 @@ AbstractionPattern::isFunctionParamAddressable(unsigned index) const {
|
||||
case Kind::CXXMethodType:
|
||||
case Kind::CurriedCXXMethodType:
|
||||
case Kind::PartialCurriedCXXMethodType:
|
||||
case Kind::CXXFunctionalConstructorType:
|
||||
case Kind::Type:
|
||||
case Kind::Discard: {
|
||||
auto type = getType();
|
||||
@@ -1723,6 +1786,7 @@ AbstractionPattern::getLifetimeDependencies() const {
|
||||
case Kind::CXXMethodType:
|
||||
case Kind::CurriedCXXMethodType:
|
||||
case Kind::PartialCurriedCXXMethodType:
|
||||
case Kind::CXXFunctionalConstructorType:
|
||||
case Kind::Type:
|
||||
case Kind::Discard: {
|
||||
auto type = getType();
|
||||
@@ -1793,6 +1857,7 @@ AbstractionPattern AbstractionPattern::getOptionalObjectType() const {
|
||||
case Kind::CXXMethodType:
|
||||
case Kind::CurriedCXXMethodType:
|
||||
case Kind::PartialCurriedCXXMethodType:
|
||||
case Kind::CXXFunctionalConstructorType:
|
||||
case Kind::Tuple:
|
||||
case Kind::OpaqueFunction:
|
||||
case Kind::OpaqueDerivativeFunction:
|
||||
@@ -1838,6 +1903,7 @@ AbstractionPattern AbstractionPattern::getReferenceStorageReferentType() const {
|
||||
case Kind::CXXMethodType:
|
||||
case Kind::CurriedCXXMethodType:
|
||||
case Kind::PartialCurriedCXXMethodType:
|
||||
case Kind::CXXFunctionalConstructorType:
|
||||
case Kind::Tuple:
|
||||
case Kind::OpaqueFunction:
|
||||
case Kind::OpaqueDerivativeFunction:
|
||||
@@ -1882,6 +1948,7 @@ AbstractionPattern AbstractionPattern::getExistentialConstraintType() const {
|
||||
case Kind::CXXMethodType:
|
||||
case Kind::CurriedCXXMethodType:
|
||||
case Kind::PartialCurriedCXXMethodType:
|
||||
case Kind::CXXFunctionalConstructorType:
|
||||
case Kind::Tuple:
|
||||
case Kind::OpaqueFunction:
|
||||
case Kind::OpaqueDerivativeFunction:
|
||||
@@ -1972,12 +2039,15 @@ void AbstractionPattern::print(raw_ostream &out) const {
|
||||
out << ")";
|
||||
return;
|
||||
case Kind::ClangType:
|
||||
case Kind::CXXFunctionalConstructorType:
|
||||
case Kind::CurriedCFunctionAsMethodType:
|
||||
case Kind::PartialCurriedCFunctionAsMethodType:
|
||||
case Kind::CFunctionAsMethodType:
|
||||
case Kind::ObjCCompletionHandlerArgumentsType:
|
||||
out << (getKind() == Kind::ClangType
|
||||
? "AP::ClangType(" :
|
||||
getKind() == Kind::CXXFunctionalConstructorType
|
||||
? "AP::CXXFunctionalConstructorType(" :
|
||||
getKind() == Kind::CurriedCFunctionAsMethodType
|
||||
? "AP::CurriedCFunctionAsMethodType(" :
|
||||
getKind() == Kind::PartialCurriedCFunctionAsMethodType
|
||||
@@ -2162,6 +2232,7 @@ const {
|
||||
case Kind::CXXMethodType:
|
||||
case Kind::CurriedCXXMethodType:
|
||||
case Kind::PartialCurriedCXXMethodType:
|
||||
case Kind::CXXFunctionalConstructorType:
|
||||
case Kind::ClangType:
|
||||
case Kind::Type:
|
||||
case Kind::Discard:
|
||||
@@ -2222,6 +2293,7 @@ AbstractionPattern::getResultConvention(TypeConverter &TC) const {
|
||||
case Kind::CXXMethodType:
|
||||
case Kind::CurriedCXXMethodType:
|
||||
case Kind::PartialCurriedCXXMethodType:
|
||||
case Kind::CXXFunctionalConstructorType:
|
||||
// Function types are always passed directly
|
||||
return Direct;
|
||||
|
||||
@@ -2263,6 +2335,7 @@ AbstractionPattern::getParameterConvention(TypeConverter &TC) const {
|
||||
case Kind::CXXMethodType:
|
||||
case Kind::CurriedCXXMethodType:
|
||||
case Kind::PartialCurriedCXXMethodType:
|
||||
case Kind::CXXFunctionalConstructorType:
|
||||
// Function types are always passed directly
|
||||
return Direct;
|
||||
|
||||
@@ -2290,6 +2363,7 @@ AbstractionPattern::getErrorConvention(TypeConverter &TC) const {
|
||||
return Indirect;
|
||||
|
||||
case Kind::ClangType:
|
||||
case Kind::CXXFunctionalConstructorType:
|
||||
case Kind::Type:
|
||||
case Kind::Discard:
|
||||
// Pass according to the formal type.
|
||||
@@ -2362,6 +2436,7 @@ AbstractionPattern::operator==(const AbstractionPattern &other) const {
|
||||
&& GenericSig == other.GenericSig;
|
||||
|
||||
case Kind::ClangType:
|
||||
case Kind::CXXFunctionalConstructorType:
|
||||
return OrigType == other.OrigType
|
||||
&& GenericSig == other.GenericSig
|
||||
&& ClangType == other.ClangType;
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "swift/AST/ForeignInfo.h"
|
||||
#include "swift/AST/GenericEnvironment.h"
|
||||
#include "swift/AST/LocalArchetypeRequirementCollector.h"
|
||||
#include "swift/AST/ASTMangler.h"
|
||||
#include "swift/AST/Module.h"
|
||||
#include "swift/AST/ModuleLoader.h"
|
||||
#include "swift/AST/TypeCheckRequests.h"
|
||||
@@ -46,6 +47,7 @@
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/SaveAndRestore.h"
|
||||
#include "llvm/Support/SipHash.h"
|
||||
|
||||
using namespace swift;
|
||||
using namespace swift::Lowering;
|
||||
@@ -1042,6 +1044,162 @@ CanSILFunctionType SILFunctionType::getAutoDiffDerivativeFunctionType(
|
||||
return cachedResult;
|
||||
}
|
||||
|
||||
static void hashStringForFunctionType(SILModule *M, CanSILFunctionType type,
|
||||
raw_ostream &Out,
|
||||
GenericEnvironment *genericEnv);
|
||||
|
||||
static void hashStringForType(SILModule *M, CanType Ty, raw_ostream &Out,
|
||||
GenericEnvironment *genericEnv) {
|
||||
if (Ty->isAnyClassReferenceType()) {
|
||||
// Any class type has to be hashed opaquely.
|
||||
Out << "-class";
|
||||
} else if (isa<AnyMetatypeType>(Ty)) {
|
||||
// Any metatype has to be hashed opaquely.
|
||||
Out << "-metatype";
|
||||
} else if (auto UnwrappedTy = Ty->getOptionalObjectType()) {
|
||||
if (UnwrappedTy->isBridgeableObjectType()) {
|
||||
// Optional<T> is compatible with T when T is class-based.
|
||||
hashStringForType(M, UnwrappedTy->getCanonicalType(), Out, genericEnv);
|
||||
} else if (UnwrappedTy->is<MetatypeType>()) {
|
||||
// Optional<T> is compatible with T when T is a metatype.
|
||||
hashStringForType(M, UnwrappedTy->getCanonicalType(), Out, genericEnv);
|
||||
} else {
|
||||
// Optional<T> is direct if and only if T is.
|
||||
Out << "Optional<";
|
||||
hashStringForType(M, UnwrappedTy->getCanonicalType(), Out, genericEnv);
|
||||
Out << ">";
|
||||
}
|
||||
} else if (auto ETy = dyn_cast<ExistentialType>(Ty)) {
|
||||
// Look through existential types
|
||||
hashStringForType(M, ETy->getConstraintType()->getCanonicalType(),
|
||||
Out, genericEnv);
|
||||
} else if (auto GTy = dyn_cast<AnyGenericType>(Ty)) {
|
||||
// For generic and non-generic value types, use the mangled declaration
|
||||
// name, and ignore all generic arguments.
|
||||
NominalTypeDecl *nominal = cast<NominalTypeDecl>(GTy->getDecl());
|
||||
Out << Mangle::ASTMangler(Ty->getASTContext()).mangleNominalType(nominal);
|
||||
} else if (auto FTy = dyn_cast<SILFunctionType>(Ty)) {
|
||||
Out << "(";
|
||||
hashStringForFunctionType(M, FTy, Out, genericEnv);
|
||||
Out << ")";
|
||||
} else {
|
||||
Out << "-";
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static void hashStringForList(SILModule *M, const ArrayRef<T> &list,
|
||||
raw_ostream &Out, GenericEnvironment *genericEnv,
|
||||
const SILFunctionType *fnType) {
|
||||
for (auto paramOrRetVal : list) {
|
||||
if (paramOrRetVal.isFormalIndirect()) {
|
||||
// Indirect params and return values have to be opaque.
|
||||
Out << "-indirect";
|
||||
} else {
|
||||
CanType Ty = M ? paramOrRetVal.getArgumentType(
|
||||
*M, fnType, M->getMaximalTypeExpansionContext())
|
||||
: paramOrRetVal.getInterfaceType();
|
||||
if (Ty->hasTypeParameter())
|
||||
Ty = genericEnv->mapTypeIntoEnvironment(Ty)->getCanonicalType();
|
||||
hashStringForType(M, Ty, Out, genericEnv);
|
||||
}
|
||||
Out << ":";
|
||||
}
|
||||
}
|
||||
|
||||
static void hashStringForList(SILModule *M, const ArrayRef<SILResultInfo> &list,
|
||||
raw_ostream &Out, GenericEnvironment *genericEnv,
|
||||
const SILFunctionType *fnType) {
|
||||
for (auto paramOrRetVal : list) {
|
||||
if (paramOrRetVal.isFormalIndirect()) {
|
||||
// Indirect params and return values have to be opaque.
|
||||
Out << "-indirect";
|
||||
} else {
|
||||
CanType Ty = M ? paramOrRetVal.getReturnValueType(
|
||||
*M, fnType, M->getMaximalTypeExpansionContext())
|
||||
: paramOrRetVal.getInterfaceType();
|
||||
if (Ty->hasTypeParameter())
|
||||
Ty = genericEnv->mapTypeIntoEnvironment(Ty)->getCanonicalType();
|
||||
hashStringForType(M, Ty, Out, genericEnv);
|
||||
}
|
||||
Out << ":";
|
||||
}
|
||||
}
|
||||
|
||||
static void hashStringForFunctionType(SILModule *M, CanSILFunctionType type,
|
||||
raw_ostream &Out,
|
||||
GenericEnvironment *genericEnv) {
|
||||
Out << (type->isCoroutine() ? "coroutine" : "function") << ":";
|
||||
Out << type->getNumParameters() << ":";
|
||||
hashStringForList(M, type->getParameters(), Out, genericEnv, type);
|
||||
Out << type->getNumResults() << ":";
|
||||
hashStringForList(M, type->getResults(), Out, genericEnv, type);
|
||||
if (type->isCoroutine()) {
|
||||
Out << type->getNumYields() << ":";
|
||||
hashStringForList(M, type->getYields(), Out, genericEnv, type);
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t SILFunctionType::getPointerAuthDiscriminator(SILModule *M) {
|
||||
// The hash we need to do here ignores:
|
||||
// - thickness, so that we can promote thin-to-thick without rehashing;
|
||||
// - error results, so that we can promote nonthrowing-to-throwing
|
||||
// without rehashing;
|
||||
// - isolation, so that global actor annotations can change in the SDK
|
||||
// without breaking compatibility and so that we can erase it to
|
||||
// nonisolated without rehashing;
|
||||
// - types of indirect arguments/retvals, so they can be substituted freely;
|
||||
// - types of class arguments/retvals
|
||||
// - types of metatype arguments/retvals
|
||||
// See isABICompatibleWith and areABICompatibleParamsOrReturns in
|
||||
// SILFunctionType.cpp.
|
||||
|
||||
SmallString<32> Buffer;
|
||||
llvm::raw_svector_ostream Out(Buffer);
|
||||
auto genericSig = getInvocationGenericSignature();
|
||||
hashStringForFunctionType(
|
||||
M, CanSILFunctionType(this), Out,
|
||||
genericSig.getCanonicalSignature().getGenericEnvironment());
|
||||
return llvm::getPointerAuthStableSipHash(Out.str());
|
||||
}
|
||||
|
||||
uint16_t SILFunctionType::getCoroutineYieldTypesDiscriminator(SILModule &M) {
|
||||
SmallString<32> buffer;
|
||||
llvm::raw_svector_ostream out(buffer);
|
||||
auto genericSig = getInvocationGenericSignature();
|
||||
auto *genericEnv = genericSig.getCanonicalSignature().getGenericEnvironment();
|
||||
|
||||
out << [&]() -> StringRef {
|
||||
switch (getCoroutineKind()) {
|
||||
case SILCoroutineKind::YieldMany: return "yield_many:";
|
||||
case SILCoroutineKind::YieldOnce: return "yield_once:";
|
||||
case SILCoroutineKind::YieldOnce2: return "yield_once_2:";
|
||||
case SILCoroutineKind::None: llvm_unreachable("not a coroutine");
|
||||
}
|
||||
llvm_unreachable("bad coroutine kind");
|
||||
}();
|
||||
|
||||
out << getNumYields() << ":";
|
||||
|
||||
for (auto yield: getYields()) {
|
||||
// We can't mangle types on inout and indirect yields because they're
|
||||
// abstractable.
|
||||
if (yield.isIndirectInOut()) {
|
||||
out << "inout";
|
||||
} else if (yield.isFormalIndirect()) {
|
||||
out << "indirect";
|
||||
} else {
|
||||
CanType Ty = yield.getArgumentType(M, this,
|
||||
M.getMaximalTypeExpansionContext());
|
||||
if (Ty->hasTypeParameter())
|
||||
Ty = genericEnv->mapTypeIntoEnvironment(Ty)->getCanonicalType();
|
||||
hashStringForType(&M, Ty, out, genericEnv);
|
||||
}
|
||||
out << ":";
|
||||
}
|
||||
return llvm::getPointerAuthStableSipHash(out.str());
|
||||
}
|
||||
|
||||
CanSILFunctionType SILFunctionType::getAutoDiffTransposeFunctionType(
|
||||
IndexSubset *parameterIndices, Lowering::TypeConverter &TC,
|
||||
LookupConformanceFn lookupConformance,
|
||||
@@ -4348,7 +4506,26 @@ static CanSILFunctionType getUncachedSILFunctionTypeForConstant(
|
||||
}
|
||||
|
||||
// Does this constant have a preferred abstraction pattern set?
|
||||
AbstractionPattern origType = [&]{
|
||||
AbstractionPattern origType = [&] {
|
||||
// If this is a constructor of std::function which was synthesized by
|
||||
// ClangImporter, the SIL type of the closure parameter needs to match the
|
||||
// Clang convention. For instance, directness of parameters needs to
|
||||
// match. This needs special handling, because the constructor is
|
||||
// synthesized as Swift AST, and therefore isn't considered foreign, but
|
||||
// at the same time requires a Clang abstraction pattern.
|
||||
if (auto ctor = dyn_cast_or_null<ConstructorDecl>(constant.getDecl())) {
|
||||
if (auto parentStruct = ctor->getParent()->getSelfStructDecl()) {
|
||||
if (auto functionTypeDecl = dyn_cast_or_null<clang::CXXRecordDecl>(
|
||||
parentStruct->getClangDecl())) {
|
||||
auto clangImporter = TC.Context.getClangModuleLoader();
|
||||
if (clangImporter->needsClosureConstructor(functionTypeDecl) ||
|
||||
clangImporter->isSwiftFunctionWrapper(functionTypeDecl)) {
|
||||
return AbstractionPattern::getCXXFunctionalConstructor(
|
||||
origLoweredInterfaceType, functionTypeDecl);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (auto closureInfo = TC.getClosureTypeInfo(constant)) {
|
||||
return closureInfo->OrigType;
|
||||
} else {
|
||||
|
||||
@@ -1081,6 +1081,10 @@ void SILModule::moveAfter(SILModule::iterator moveAfter, SILFunction *fn) {
|
||||
getFunctionList().insertAfter(moveAfter, fn);
|
||||
}
|
||||
|
||||
TypeExpansionContext SILModule::getMaximalTypeExpansionContext() const {
|
||||
return TypeExpansionContext::maximal(getAssociatedContext(), isWholeModule());
|
||||
}
|
||||
|
||||
SILProperty *
|
||||
SILProperty::create(SILModule &M, unsigned Serialized, AbstractStorageDecl *Decl,
|
||||
std::optional<KeyPathPatternComponent> Component) {
|
||||
|
||||
@@ -5542,6 +5542,19 @@ unsigned TypeConverter::countNumberOfFields(SILType Ty,
|
||||
return std::max(fieldsCount, 1U);
|
||||
}
|
||||
|
||||
uint16_t FunctionType::getPointerAuthDiscriminator(
|
||||
ModuleDecl &m, const clang::FunctionType *clangType) {
|
||||
TypeConverter converter(m);
|
||||
AbstractionPattern pattern =
|
||||
clangType ? AbstractionPattern(getCanonicalType(), clangType)
|
||||
: AbstractionPattern(getCanonicalType());
|
||||
auto &typeLowering =
|
||||
converter.getTypeLowering(pattern, Type(static_cast<TypeBase *>(this)),
|
||||
TypeExpansionContext::minimal());
|
||||
auto functionType = typeLowering.getLoweredType().getAs<SILFunctionType>();
|
||||
return functionType->getPointerAuthDiscriminator(nullptr);
|
||||
}
|
||||
|
||||
void TypeLowering::print(llvm::raw_ostream &os) const {
|
||||
auto BOOL = [&](bool b) -> StringRef {
|
||||
if (b)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <ptrauth.h>
|
||||
|
||||
/// Used for std::string conformance to Swift.Hashable
|
||||
typedef std::hash<std::string> __swift_interopHashOfString;
|
||||
@@ -41,3 +43,57 @@ inline std::chrono::microseconds __swift_interopMakeChronoMicroseconds(int64_t m
|
||||
inline std::chrono::nanoseconds __swift_interopMakeChronoNanoseconds(int64_t nanoseconds) {
|
||||
return std::chrono::nanoseconds(nanoseconds);
|
||||
}
|
||||
|
||||
namespace __swift_interop {
|
||||
extern "C" {
|
||||
void swift_retain(void *_Nonnull) noexcept;
|
||||
void swift_release(void *_Nonnull) noexcept;
|
||||
}
|
||||
} // namespace __swift_interop
|
||||
|
||||
struct __swift_interop_closure {
|
||||
void *_Nonnull func;
|
||||
void *_Nullable context;
|
||||
};
|
||||
|
||||
template <uint16_t PtrAuthTypeDiscriminator, typename Result, typename... Args>
|
||||
struct __SwiftFunctionWrapper {
|
||||
/// C++ function type that is equivalent to the lowered Swift closure type.
|
||||
/// Note that Clang might pass the parameters or the return value indirectly.
|
||||
using LoweredFunction = Result
|
||||
__attribute__((swiftcall)) (Args...,
|
||||
void *_Nullable __attribute__((swift_context)));
|
||||
|
||||
/// Swift will pretend that the type of this field is a Swift closure type.
|
||||
__swift_interop_closure closure;
|
||||
|
||||
Result operator()(Args... args) const {
|
||||
return ((LoweredFunction *)ptrauth_auth_and_resign(
|
||||
closure.func, ptrauth_key_asia, PtrAuthTypeDiscriminator,
|
||||
ptrauth_key_function_pointer, 0))(std::forward<Args>(args)...,
|
||||
closure.context);
|
||||
}
|
||||
|
||||
// A memberwise constructor is synthesized by Swift.
|
||||
|
||||
__SwiftFunctionWrapper() = delete;
|
||||
__SwiftFunctionWrapper &operator=(const __SwiftFunctionWrapper &other) = delete;
|
||||
__SwiftFunctionWrapper &operator=(__SwiftFunctionWrapper &&other) = delete;
|
||||
|
||||
__SwiftFunctionWrapper(const __SwiftFunctionWrapper &other) noexcept {
|
||||
closure = other.closure;
|
||||
if (closure.context)
|
||||
__swift_interop::swift_retain(closure.context);
|
||||
}
|
||||
|
||||
__SwiftFunctionWrapper(__SwiftFunctionWrapper &&other) noexcept {
|
||||
closure = other.closure;
|
||||
other.closure.func = nullptr;
|
||||
other.closure.context = nullptr;
|
||||
}
|
||||
|
||||
~__SwiftFunctionWrapper() {
|
||||
if (closure.context)
|
||||
__swift_interop::swift_release(closure.context);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -4,9 +4,49 @@
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
using FunctionVoidToVoid = std::function<void()>;
|
||||
using FunctionVoidToInt = std::function<int()>;
|
||||
using FunctionIntToVoid = std::function<void(int)>;
|
||||
using FunctionIntToInt = std::function<int(int)>;
|
||||
using FunctionConstIntToInt = std::function<int(const int)>;
|
||||
using FunctionConstRefIntToInt = std::function<int(const int&)>;
|
||||
using FunctionIntIntToInt = std::function<int(int, int)>;
|
||||
using FunctionStringToString = std::function<std::string(std::string)>;
|
||||
using FunctionStringToStringConstRef = std::function<std::string(const std::string&)>;
|
||||
using FunctionConstRefStringToString = std::function<std::string(const std::string&)>;
|
||||
using FunctionConstRefStringToConstRefString = std::function<const std::string&(const std::string&)>;
|
||||
|
||||
struct HasDeletedCopyCtor {
|
||||
int value;
|
||||
HasDeletedCopyCtor(int value) : value(value) {}
|
||||
HasDeletedCopyCtor(const HasDeletedCopyCtor &other) = delete;
|
||||
HasDeletedCopyCtor(HasDeletedCopyCtor &&other) = default;
|
||||
HasDeletedCopyCtor& operator=(const HasDeletedCopyCtor &other) = delete;
|
||||
HasDeletedCopyCtor& operator=(HasDeletedCopyCtor &&other) = default;
|
||||
~HasDeletedCopyCtor() = default;
|
||||
};
|
||||
using FunctionIntToHasDeletedCopyCtor = std::function<HasDeletedCopyCtor(int)>;
|
||||
using FunctionConstRefHasDeletedCopyCtorToVoid = std::function<void(const HasDeletedCopyCtor&)>;
|
||||
using FunctionConstRefHasDeletedCopyCtorToInt = std::function<int(const HasDeletedCopyCtor&)>;
|
||||
using FunctionHasDeletedCopyCtor = std::function<HasDeletedCopyCtor(const HasDeletedCopyCtor&)>;
|
||||
|
||||
int invokeFunctionConstRefHasDeletedCopyCtorToInt(FunctionConstRefHasDeletedCopyCtorToInt f) {
|
||||
HasDeletedCopyCtor arg(123);
|
||||
return f(arg);
|
||||
}
|
||||
|
||||
struct NonTrivialHasDeletedCopyCtor {
|
||||
int value;
|
||||
bool destroyed = false;
|
||||
NonTrivialHasDeletedCopyCtor(int value) : value(value) {}
|
||||
NonTrivialHasDeletedCopyCtor(const NonTrivialHasDeletedCopyCtor &other) = delete;
|
||||
NonTrivialHasDeletedCopyCtor(NonTrivialHasDeletedCopyCtor &&other) = default;
|
||||
NonTrivialHasDeletedCopyCtor& operator=(const NonTrivialHasDeletedCopyCtor &other) = delete;
|
||||
NonTrivialHasDeletedCopyCtor& operator=(NonTrivialHasDeletedCopyCtor &&other) = default;
|
||||
~NonTrivialHasDeletedCopyCtor() { destroyed = true; } // makes the type non-trivial
|
||||
};
|
||||
using FunctionIntToNonTrivialHasDeletedCopyCtor = std::function<NonTrivialHasDeletedCopyCtor(int)>;
|
||||
using FunctionConstRefNonTrivialHasDeletedCopyCtorToVoid = std::function<void(const NonTrivialHasDeletedCopyCtor&)>;
|
||||
using FunctionNonTrivialHasDeletedCopyCtor = std::function<NonTrivialHasDeletedCopyCtor(const NonTrivialHasDeletedCopyCtor&)>;
|
||||
|
||||
inline FunctionIntToInt getIdentityFunction() {
|
||||
return [](int x) { return x; };
|
||||
@@ -16,12 +56,34 @@ inline bool isEmptyFunction(FunctionIntToInt f) { return !(bool)f; }
|
||||
|
||||
inline int invokeFunction(FunctionIntToInt f, int x) { return f(x); }
|
||||
|
||||
int invokeFunctionIntToIntTwice(FunctionIntToInt f, int i) {
|
||||
return f(f(i));
|
||||
}
|
||||
int invokeFunctionIntToIntByConstRefTwice(const FunctionIntToInt& f, int i) {
|
||||
return f(f(i));
|
||||
}
|
||||
int invokeFunctionIntToIntByRValueRefTwice(const FunctionIntToInt& f, int i) {
|
||||
return f(f(i));
|
||||
}
|
||||
|
||||
std::string invokeFunctionTwice(FunctionStringToString f, std::string s) {
|
||||
return f(f(s));
|
||||
}
|
||||
|
||||
std::string invokeFunctionTwiceConstRef(FunctionStringToStringConstRef f, std::string s) {
|
||||
std::string invokeFunctionByConstRefTwice(const FunctionStringToString& f, std::string s) {
|
||||
return f(f(s));
|
||||
}
|
||||
|
||||
std::string invokeFunctionTwiceConstRef(FunctionConstRefStringToString f, std::string s) {
|
||||
return f(f(s));
|
||||
}
|
||||
|
||||
std::string invokeFunctionTwiceConstRefX2(FunctionConstRefStringToConstRefString f, std::string s) {
|
||||
return f(f(s));
|
||||
}
|
||||
|
||||
template<typename Func>
|
||||
int invokeTemplatedCallableIntToInt(Func f) { return f(123); };
|
||||
template<typename Func>
|
||||
int invokeTemplatedCallableByConstRefIntToInt(const Func& f) { return f(321); };
|
||||
|
||||
#endif // TEST_INTEROP_CXX_STDLIB_INPUTS_STD_FUNCTION_H
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
// RUN: %target-typecheck-verify-swift -I %S/Inputs -cxx-interoperability-mode=upcoming-swift
|
||||
|
||||
import StdFunction
|
||||
|
||||
var ctx: Int32 = 123
|
||||
let _ = FunctionIntIntToInt({ a, b in a + b + ctx }) // OK
|
||||
|
||||
var stringCtx = std.string("abc")
|
||||
let _ = invokeFunctionTwiceConstRefX2(.init({ _ in stringCtx }), std.string("prefix")) // expected-error {{cannot convert value of type 'std.string'}}
|
||||
|
||||
let _ = invokeTemplatedCallableIntToInt(.init({ x in x + 1 })) // expected-error {{cannot infer contextual base in reference to member 'init'}}
|
||||
let _ = invokeTemplatedCallableIntToInt(FunctionIntToInt({ x in x + 1 })) // OK
|
||||
|
||||
let _ = invokeTemplatedCallableByConstRefIntToInt(.init({ x in x + 1 })) // expected-error {{cannot infer contextual base in reference to member 'init'}}
|
||||
let _ = invokeTemplatedCallableByConstRefIntToInt(FunctionIntToInt({ x in x + 1 })) // OK
|
||||
@@ -55,11 +55,258 @@ StdFunctionTestSuite.test("FunctionStringToString init from closure and pass as
|
||||
expectEqual(std.string("prefixabcabc"), res)
|
||||
}
|
||||
|
||||
StdFunctionTestSuite.test("FunctionStringToStringConstRef init from closure and pass as parameter") {
|
||||
StdFunctionTestSuite.test("FunctionConstRefStringToString init from closure and pass as parameter") {
|
||||
let res = invokeFunctionTwiceConstRef(.init({ $0 + std.string("abc") }),
|
||||
std.string("prefix"))
|
||||
expectEqual(std.string("prefixabcabc"), res)
|
||||
}
|
||||
#endif
|
||||
|
||||
StdFunctionTestSuite.test("FunctionVoidToVoid init from thick closure and call") {
|
||||
var counter = 0
|
||||
let f1 = FunctionVoidToVoid { counter += 1 }
|
||||
expectEqual(0, counter)
|
||||
f1()
|
||||
expectEqual(1, counter)
|
||||
f1()
|
||||
expectEqual(2, counter)
|
||||
}
|
||||
|
||||
StdFunctionTestSuite.test("FunctionVoidToInt init from thick closure and call") {
|
||||
let external: Int32 = 123
|
||||
let f1 = FunctionVoidToInt { external }
|
||||
expectEqual(123, f1())
|
||||
}
|
||||
|
||||
StdFunctionTestSuite.test("FunctionIntToVoid init from thick closure and call") {
|
||||
var counter: Int32 = 0
|
||||
let f1 = FunctionIntToVoid { counter += $0 }
|
||||
expectEqual(0, counter)
|
||||
f1(5)
|
||||
expectEqual(5, counter)
|
||||
f1(10)
|
||||
expectEqual(15, counter)
|
||||
}
|
||||
|
||||
StdFunctionTestSuite.test("FunctionIntToInt init from thick closure and call") {
|
||||
let external: Int32 = 123
|
||||
let f1 = FunctionIntToInt { $0 + external }
|
||||
expectEqual(123, f1(0))
|
||||
expectEqual(124, f1(1))
|
||||
}
|
||||
|
||||
StdFunctionTestSuite.test("FunctionConstIntToInt init from thick closure and call") {
|
||||
let external: Int32 = 321
|
||||
let f1 = FunctionConstIntToInt { $0 + external }
|
||||
expectEqual(321, f1(0))
|
||||
expectEqual(322, f1(1))
|
||||
}
|
||||
|
||||
StdFunctionTestSuite.test("FunctionConstRefIntToInt init from thick closure and call") {
|
||||
let external: Int32 = 456
|
||||
let f1 = FunctionConstIntToInt { $0 + external }
|
||||
expectEqual(456, f1(0))
|
||||
expectEqual(457, f1(1))
|
||||
}
|
||||
|
||||
StdFunctionTestSuite.test("FunctionIntIntToInt init from thick closure and call") {
|
||||
let immutableExternal: Int32 = 10
|
||||
let f1 = FunctionIntIntToInt({ a, b in
|
||||
a - b + immutableExternal
|
||||
})
|
||||
expectEqual(11, f1(3, 2))
|
||||
expectEqual(9, f1(2, 3))
|
||||
|
||||
var mutableExternal: Int32 = -100
|
||||
let f2 = FunctionIntIntToInt({ a, b in
|
||||
a - b + mutableExternal
|
||||
})
|
||||
mutableExternal = 20
|
||||
expectEqual(21, f2(3, 2))
|
||||
mutableExternal = 0
|
||||
expectEqual(1, f2(3, 2))
|
||||
|
||||
var modifiedExternal: Int32 = 20
|
||||
let f3 = FunctionIntIntToInt({ a, b in
|
||||
let result = a - b + modifiedExternal
|
||||
modifiedExternal = a + b
|
||||
return result
|
||||
})
|
||||
expectEqual(21, f3(3, 2))
|
||||
expectEqual(6, f3(3, 2))
|
||||
expectEqual(4, f3(1, 2))
|
||||
expectEqual(2, f3(1, 2))
|
||||
|
||||
struct MyContext {
|
||||
var x: Int32
|
||||
var y: Int32
|
||||
var z: Int32
|
||||
}
|
||||
var external = MyContext(x: 123, y: 456, z: 789)
|
||||
let closure: (Int32, Int32) -> Int32 = {
|
||||
let r = $0 + $1 + external.x
|
||||
external.y = r
|
||||
return r
|
||||
}
|
||||
let f4 = FunctionIntIntToInt(closure)
|
||||
expectEqual(246, f4(123, 0))
|
||||
expectEqual(124, f4(1, 0))
|
||||
expectEqual(122, f4(-1, 0))
|
||||
}
|
||||
|
||||
StdFunctionTestSuite.test("FunctionIntToInt init from thick closure and pass as parameter") {
|
||||
let immutableExternal: Int32 = 10
|
||||
let res1 = invokeFunctionIntToIntTwice(.init({ $0 + immutableExternal }),
|
||||
123)
|
||||
expectEqual(143, res1)
|
||||
|
||||
var modifiedExternal: Int32 = 20
|
||||
let res2 = invokeFunctionIntToIntTwice(.init({ a in
|
||||
modifiedExternal += a
|
||||
return a + modifiedExternal
|
||||
}), 7)
|
||||
expectEqual(95, res2)
|
||||
}
|
||||
|
||||
StdFunctionTestSuite.test("FunctionIntToInt init from thick closure and pass as const ref parameter") {
|
||||
let immutableExternal: Int32 = 10
|
||||
let res1 = invokeFunctionIntToIntByConstRefTwice(.init({ $0 + immutableExternal }),
|
||||
123)
|
||||
expectEqual(143, res1)
|
||||
|
||||
var modifiedExternal: Int32 = 20
|
||||
let res2 = invokeFunctionIntToIntByConstRefTwice(.init({ a in
|
||||
modifiedExternal += a
|
||||
return a + modifiedExternal
|
||||
}), 7)
|
||||
expectEqual(95, res2)
|
||||
}
|
||||
|
||||
StdFunctionTestSuite.test("FunctionIntToInt init from thick closure and pass as rvalue ref parameter") {
|
||||
let immutableExternal: Int32 = 10
|
||||
let res1 = invokeFunctionIntToIntByRValueRefTwice(.init({ $0 + immutableExternal }),
|
||||
123)
|
||||
expectEqual(143, res1)
|
||||
|
||||
var modifiedExternal: Int32 = 20
|
||||
let res2 = invokeFunctionIntToIntByRValueRefTwice(.init({ a in
|
||||
modifiedExternal += a
|
||||
return a + modifiedExternal
|
||||
}), 7)
|
||||
expectEqual(95, res2)
|
||||
}
|
||||
|
||||
StdFunctionTestSuite.test("FunctionStringToString init from thick closure and pass as parameter") {
|
||||
var modifiedExternal = std.string()
|
||||
let res = invokeFunctionTwice(.init({
|
||||
let result = $0 + std.string("abc")
|
||||
modifiedExternal = result
|
||||
return result
|
||||
}), std.string("prefix_"))
|
||||
expectEqual(std.string("prefix_abcabc"), res)
|
||||
expectEqual(std.string("prefix_abcabc"), modifiedExternal)
|
||||
}
|
||||
|
||||
StdFunctionTestSuite.test("FunctionStringToString init from thick closure and pass as const ref parameter") {
|
||||
var modifiedExternal = std.string()
|
||||
let res = invokeFunctionByConstRefTwice(.init({
|
||||
let result = $0 + std.string("abc")
|
||||
modifiedExternal = result
|
||||
return result
|
||||
}), std.string("prefix_"))
|
||||
expectEqual(std.string("prefix_abcabc"), res)
|
||||
expectEqual(std.string("prefix_abcabc"), modifiedExternal)
|
||||
}
|
||||
|
||||
StdFunctionTestSuite.test("FunctionIntToHasDeletedCopyCtor init from thick closure and call") {
|
||||
let f1 = FunctionIntToHasDeletedCopyCtor { HasDeletedCopyCtor($0) }
|
||||
let res1 = f1(50)
|
||||
expectEqual(50, res1.value)
|
||||
}
|
||||
|
||||
StdFunctionTestSuite.test("FunctionConstRefHasDeletedCopyCtorToInt init from thick closure and pass as parameter") {
|
||||
var external: Int32 = 10
|
||||
let f1 = FunctionConstRefHasDeletedCopyCtorToInt {
|
||||
let res = $0.value + external
|
||||
external += 5
|
||||
return res
|
||||
}
|
||||
let res1 = invokeFunctionConstRefHasDeletedCopyCtorToInt(f1)
|
||||
expectEqual(133, res1)
|
||||
let res2 = invokeFunctionConstRefHasDeletedCopyCtorToInt(f1)
|
||||
expectEqual(138, res2)
|
||||
}
|
||||
|
||||
StdFunctionTestSuite.test("FunctionConstRefHasDeletedCopyCtorToVoid init from thick closure and call") {
|
||||
var counter: Int32 = 0
|
||||
let f1 = FunctionConstRefHasDeletedCopyCtorToVoid { counter += $0.value }
|
||||
expectEqual(0, counter)
|
||||
f1(HasDeletedCopyCtor(50))
|
||||
expectEqual(50, counter)
|
||||
f1(HasDeletedCopyCtor(100))
|
||||
expectEqual(150, counter)
|
||||
}
|
||||
|
||||
StdFunctionTestSuite.test("FunctionHasDeletedCopyCtor init from thick closure and call") {
|
||||
var external: Int32 = 10
|
||||
let f1 = FunctionHasDeletedCopyCtor({ h in
|
||||
external += 10
|
||||
return HasDeletedCopyCtor(h.value + external)
|
||||
})
|
||||
var x = HasDeletedCopyCtor(1)
|
||||
x = f1(x)
|
||||
expectEqual(21, x.value)
|
||||
x = f1(x)
|
||||
expectEqual(51, x.value)
|
||||
}
|
||||
|
||||
StdFunctionTestSuite.test("FunctionIntToNonTrivialHasDeletedCopyCtor init from thick closure and call") {
|
||||
let f1 = FunctionIntToNonTrivialHasDeletedCopyCtor { NonTrivialHasDeletedCopyCtor($0) }
|
||||
let res1 = f1(150)
|
||||
expectEqual(150, res1.value)
|
||||
}
|
||||
|
||||
StdFunctionTestSuite.test("FunctionConstRefNonTrivialHasDeletedCopyCtorToVoid init from thick closure and call") {
|
||||
var counter: Int32 = 0
|
||||
let f1 = FunctionConstRefNonTrivialHasDeletedCopyCtorToVoid { counter += $0.value }
|
||||
expectEqual(0, counter)
|
||||
f1(NonTrivialHasDeletedCopyCtor(50))
|
||||
expectEqual(50, counter)
|
||||
f1(NonTrivialHasDeletedCopyCtor(100))
|
||||
expectEqual(150, counter)
|
||||
}
|
||||
|
||||
StdFunctionTestSuite.test("FunctionNonTrivialHasDeletedCopyCtor init from thick closure and call") {
|
||||
var external: Int32 = 10
|
||||
let f1 = FunctionNonTrivialHasDeletedCopyCtor({ h in
|
||||
external += 10
|
||||
return NonTrivialHasDeletedCopyCtor(h.value + external)
|
||||
})
|
||||
var x = NonTrivialHasDeletedCopyCtor(1)
|
||||
x = f1(x)
|
||||
expectEqual(21, x.value)
|
||||
x = f1(x)
|
||||
expectEqual(51, x.value)
|
||||
}
|
||||
|
||||
StdFunctionTestSuite.test("FunctionIntToInt init from thick closure and pass as templated callable parameter") {
|
||||
var sum: Int32 = 0
|
||||
let res1 = invokeTemplatedCallableIntToInt(FunctionIntToInt({ x in
|
||||
sum += x
|
||||
return x * 2
|
||||
}))
|
||||
expectEqual(246, res1)
|
||||
expectEqual(123, sum)
|
||||
}
|
||||
|
||||
StdFunctionTestSuite.test("FunctionIntToInt init from thick closure and pass as templated callable parameter by const ref") {
|
||||
var sum: Int32 = 0
|
||||
let res1 = invokeTemplatedCallableByConstRefIntToInt(FunctionIntToInt({ x in
|
||||
sum += x
|
||||
return x * 2
|
||||
}))
|
||||
expectEqual(642, res1)
|
||||
expectEqual(321, sum)
|
||||
}
|
||||
|
||||
runAllTests()
|
||||
|
||||
@@ -20,6 +20,8 @@ add_swift_unittest(SwiftASTTests
|
||||
target_link_libraries(SwiftASTTests
|
||||
PRIVATE
|
||||
swiftAST
|
||||
swiftClangImporter
|
||||
swiftSIL
|
||||
# FIXME: Circular dependencies.
|
||||
swiftParse
|
||||
swiftSema
|
||||
|
||||
@@ -6,4 +6,5 @@ add_swift_unittest(SwiftIDETests
|
||||
target_link_libraries(SwiftIDETests
|
||||
PRIVATE
|
||||
swiftIDE
|
||||
swiftClangImporter
|
||||
)
|
||||
|
||||
@@ -6,10 +6,10 @@ add_swift_unittest(SwiftParseTests
|
||||
|
||||
target_link_libraries(SwiftParseTests
|
||||
PRIVATE
|
||||
swiftSIL
|
||||
swiftClangImporter
|
||||
swiftParse
|
||||
swiftAST
|
||||
swiftClangImporter
|
||||
swiftSIL
|
||||
# FIXME: Sema must go last because of circular dependencies with AST.
|
||||
swiftSema
|
||||
)
|
||||
|
||||
@@ -13,6 +13,8 @@ add_swift_unittest(swiftSemaTests
|
||||
target_link_libraries(swiftSemaTests
|
||||
PRIVATE
|
||||
swiftAST
|
||||
swiftClangImporter
|
||||
swiftSIL
|
||||
swiftSema
|
||||
swiftSerialization)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user