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:
Egor Zhdan
2025-12-10 13:35:34 +00:00
committed by GitHub
27 changed files with 1086 additions and 257 deletions
+18
View File
@@ -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;
+12
View File
@@ -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);
+26 -1
View File
@@ -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:
+2
View File
@@ -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,
+2
View File
@@ -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,
+59
View File
@@ -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);
+35 -1
View File
@@ -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,
+4
View File
@@ -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);
+249 -1
View File
@@ -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>
+4
View File
@@ -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.
+4 -151
View File
@@ -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 *
+1 -2
View File
@@ -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
+75
View File
@@ -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;
+178 -1
View File
@@ -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 {
+4
View File
@@ -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) {
+13
View File
@@ -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);
}
};
+65 -3
View File
@@ -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
+248 -1
View File
@@ -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()
+2
View File
@@ -20,6 +20,8 @@ add_swift_unittest(SwiftASTTests
target_link_libraries(SwiftASTTests
PRIVATE
swiftAST
swiftClangImporter
swiftSIL
# FIXME: Circular dependencies.
swiftParse
swiftSema
+1
View File
@@ -6,4 +6,5 @@ add_swift_unittest(SwiftIDETests
target_link_libraries(SwiftIDETests
PRIVATE
swiftIDE
swiftClangImporter
)
+2 -2
View File
@@ -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
)
+2
View File
@@ -13,6 +13,8 @@ add_swift_unittest(swiftSemaTests
target_link_libraries(swiftSemaTests
PRIVATE
swiftAST
swiftClangImporter
swiftSIL
swiftSema
swiftSerialization)