From 92f56e7ec82eadebb994ef5fd41fd595fbb00a65 Mon Sep 17 00:00:00 2001 From: Joe Groff Date: Mon, 3 May 2021 09:17:17 -0700 Subject: [PATCH] Allow conversions from actor-bound sync function type to unbound async function type. For `async` function types, an actor constraint can be enforced by the callee by hopping executors, unlike with `sync` functions, so doesn't need to influence the outward type of the function. rdar://76248452 --- docs/ABI/Mangling.rst | 2 + include/swift/AST/ASTMangler.h | 1 + include/swift/Demangling/DemangleNodes.def | 1 + include/swift/SIL/FormalLinkage.h | 1 + lib/AST/ASTMangler.cpp | 6 ++ lib/Demangling/Demangler.cpp | 14 +++ lib/Demangling/NodePrinter.cpp | 7 ++ lib/Demangling/OldRemangler.cpp | 4 + lib/Demangling/Remangler.cpp | 5 + lib/SIL/IR/SIL.cpp | 25 +++++ lib/SILGen/ExecutorBreadcrumb.h | 7 ++ lib/SILGen/SILGen.h | 3 +- lib/SILGen/SILGenBridging.cpp | 6 +- lib/SILGen/SILGenPoly.cpp | 29 +++++- lib/SILGen/SILGenThunk.cpp | 19 +++- lib/SILOptimizer/Differentiation/Thunk.cpp | 2 +- lib/Sema/CSSimplify.cpp | 4 +- .../global_actor_function_types.swift | 7 ++ test/SILGen/hop_to_executor.swift | 99 +++++++++++++++++-- 19 files changed, 225 insertions(+), 17 deletions(-) diff --git a/docs/ABI/Mangling.rst b/docs/ABI/Mangling.rst index 6c172bcdf28..d66e62248ee 100644 --- a/docs/ABI/Mangling.rst +++ b/docs/ABI/Mangling.rst @@ -251,6 +251,8 @@ types where the metadata itself has unknown layout.) REABSTRACT-THUNK-TYPE ::= 'R' // reabstraction thunk REABSTRACT-THUNK-TYPE ::= 'r' // reabstraction thunk (obsolete) + global ::= reabstraction-thunk type 'TU' // reabstraction thunk with global actor constraint + The `from-type` and `to-type` in a reabstraction thunk helper function are always non-polymorphic ```` types. diff --git a/include/swift/AST/ASTMangler.h b/include/swift/AST/ASTMangler.h index 729c9c0eb48..aeb0d2a16dc 100644 --- a/include/swift/AST/ASTMangler.h +++ b/include/swift/AST/ASTMangler.h @@ -163,6 +163,7 @@ public: std::string mangleReabstractionThunkHelper(CanSILFunctionType ThunkType, Type FromType, Type ToType, Type SelfType, + Type GlobalActorBound, ModuleDecl *Module); /// Mangle a completion handler block implementation function, used for importing ObjC diff --git a/include/swift/Demangling/DemangleNodes.def b/include/swift/Demangling/DemangleNodes.def index 8a02f3972f7..10754df91d7 100644 --- a/include/swift/Demangling/DemangleNodes.def +++ b/include/swift/Demangling/DemangleNodes.def @@ -194,6 +194,7 @@ NODE(ProtocolWitnessTablePattern) NODE(ReabstractionThunk) NODE(ReabstractionThunkHelper) NODE(ReabstractionThunkHelperWithSelf) +NODE(ReabstractionThunkHelperWithGlobalActor) CONTEXT_NODE(ReadAccessor) NODE(RelatedEntityDeclName) NODE(RetroactiveConformance) diff --git a/include/swift/SIL/FormalLinkage.h b/include/swift/SIL/FormalLinkage.h index 512046b40a6..d1530b190a0 100644 --- a/include/swift/SIL/FormalLinkage.h +++ b/include/swift/SIL/FormalLinkage.h @@ -43,6 +43,7 @@ enum class FormalLinkage { }; FormalLinkage getDeclLinkage(const ValueDecl *decl); +FormalLinkage getTypeLinkage(CanType formalType); SILLinkage getSILLinkage(FormalLinkage linkage, ForDefinition_t forDefinition); SILLinkage diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index d7334f37fbb..4813aa6dbf8 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -379,6 +379,7 @@ std::string ASTMangler::mangleReabstractionThunkHelper( Type FromType, Type ToType, Type SelfType, + Type GlobalActorBound, ModuleDecl *Module) { Mod = Module; assert(ThunkType->getPatternSubstitutions().empty() && "not implemented"); @@ -399,6 +400,11 @@ std::string ASTMangler::mangleReabstractionThunkHelper( appendOperator("Ty"); else appendOperator("TR"); + + if (GlobalActorBound) { + appendType(GlobalActorBound); + appendOperator("TU"); + } return finalize(); } diff --git a/lib/Demangling/Demangler.cpp b/lib/Demangling/Demangler.cpp index f240434c0fc..611e74a3ef7 100644 --- a/lib/Demangling/Demangler.cpp +++ b/lib/Demangling/Demangler.cpp @@ -2537,6 +2537,20 @@ NodePointer Demangler::demangleThunkOrSpecialization() { return createNode(Node::Kind::OutlinedBridgedMethod, Params); } case 'u': return createNode(Node::Kind::AsyncFunctionPointer); + case 'U': { + auto globalActor = popNode(Node::Kind::Type); + if (!globalActor) + return nullptr; + + auto reabstraction = popNode(); + if (!reabstraction) + return nullptr; + + auto node = createNode(Node::Kind::ReabstractionThunkHelperWithGlobalActor); + node->addChild(reabstraction, *this); + node->addChild(globalActor, *this); + return node; + } case 'J': switch (peekChar()) { case 'S': diff --git a/lib/Demangling/NodePrinter.cpp b/lib/Demangling/NodePrinter.cpp index 3fc9344f10b..cfcc6a740cf 100644 --- a/lib/Demangling/NodePrinter.cpp +++ b/lib/Demangling/NodePrinter.cpp @@ -471,6 +471,7 @@ private: case Node::Kind::ReabstractionThunk: case Node::Kind::ReabstractionThunkHelper: case Node::Kind::ReabstractionThunkHelperWithSelf: + case Node::Kind::ReabstractionThunkHelperWithGlobalActor: case Node::Kind::ReadAccessor: case Node::Kind::RelatedEntityDeclName: case Node::Kind::RetroactiveConformance: @@ -1745,6 +1746,12 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) { print(Node->getChild(idx)); return nullptr; } + case Node::Kind::ReabstractionThunkHelperWithGlobalActor: { + print(Node->getChild(0)); + Printer << " with global actor constraint "; + print(Node->getChild(1)); + return nullptr; + } case Node::Kind::ReabstractionThunkHelperWithSelf: { Printer << "reabstraction thunk "; unsigned idx = 0; diff --git a/lib/Demangling/OldRemangler.cpp b/lib/Demangling/OldRemangler.cpp index 5b1bab9f6bd..f357b129f1d 100644 --- a/lib/Demangling/OldRemangler.cpp +++ b/lib/Demangling/OldRemangler.cpp @@ -755,6 +755,10 @@ void Remangler::mangleReabstractionThunk(Node *node) { Buffer << ""; } +void Remangler::mangleReabstractionThunkHelperWithGlobalActor(Node *node) { + Buffer << ""; +} + void Remangler::mangleAutoDiffFunction(Node *node, EntityContext &ctx) { Buffer << ""; } diff --git a/lib/Demangling/Remangler.cpp b/lib/Demangling/Remangler.cpp index e97ed4ce87b..6c624dad591 100644 --- a/lib/Demangling/Remangler.cpp +++ b/lib/Demangling/Remangler.cpp @@ -2125,6 +2125,11 @@ void Remangler::mangleReabstractionThunkHelperWithSelf(Node *node) { Buffer << "Ty"; } +void Remangler::mangleReabstractionThunkHelperWithGlobalActor(Node *node) { + mangleChildNodes(node); + Buffer << "TU"; +} + void Remangler::mangleAutoDiffFunctionOrSimpleThunk(Node *node, StringRef op) { auto childIt = node->begin(); while (childIt != node->end() && diff --git a/lib/SIL/IR/SIL.cpp b/lib/SIL/IR/SIL.cpp index e9c739af208..18a618a1ba5 100644 --- a/lib/SIL/IR/SIL.cpp +++ b/lib/SIL/IR/SIL.cpp @@ -141,6 +141,31 @@ bool SILModule::isTypeMetadataAccessible(CanType type) { }); } +/// Return the minimum linkage structurally required to reference the given formal type. +FormalLinkage swift::getTypeLinkage(CanType t) { + assert(t->isLegalFormalType()); + + class Walker : public TypeWalker { + public: + FormalLinkage Linkage; + Walker() : Linkage(FormalLinkage::PublicUnique) {} + + Action walkToTypePre(Type ty) override { + // Non-nominal types are always available. + auto decl = ty->getNominalOrBoundGenericNominal(); + if (!decl) + return Action::Continue; + + Linkage = std::min(Linkage, getDeclLinkage(decl)); + return Action::Continue; + } + }; + + Walker w; + t.walk(w); + return w.Linkage; +} + /// Answer whether IRGen's emitTypeMetadataForLayout can fetch metadata for /// a type, which is the necessary condition for being able to do value /// operations on the type using dynamic metadata. diff --git a/lib/SILGen/ExecutorBreadcrumb.h b/lib/SILGen/ExecutorBreadcrumb.h index 1f544e53447..efc1441f4cb 100644 --- a/lib/SILGen/ExecutorBreadcrumb.h +++ b/lib/SILGen/ExecutorBreadcrumb.h @@ -10,9 +10,16 @@ // //===----------------------------------------------------------------------===// +#include "swift/SIL/SILValue.h" + namespace swift { + +class SILLocation; + namespace Lowering { +class SILGenFunction; + /// Represents the information necessary to return to a caller's own /// active executor after making a hop to an actor for actor-isolated calls. class ExecutorBreadcrumb { diff --git a/lib/SILGen/SILGen.h b/lib/SILGen/SILGen.h index 2501521f07c..ce2ad3945c5 100644 --- a/lib/SILGen/SILGen.h +++ b/lib/SILGen/SILGen.h @@ -175,7 +175,8 @@ public: CanSILFunctionType thunkType, CanSILFunctionType fromType, CanSILFunctionType toType, - CanType dynamicSelfType); + CanType dynamicSelfType, + CanType fromGlobalActor); /// Get or create the declaration of a completion handler block /// implementation function for an ObjC API that was imported diff --git a/lib/SILGen/SILGenBridging.cpp b/lib/SILGen/SILGenBridging.cpp index 1655162c7d7..1aa0e009240 100644 --- a/lib/SILGen/SILGenBridging.cpp +++ b/lib/SILGen/SILGenBridging.cpp @@ -606,7 +606,8 @@ ManagedValue SILGenFunction::emitFuncToBlock(SILLocation loc, auto thunk = SGM.getOrCreateReabstractionThunk(invokeTy, loweredFuncUnsubstTy, loweredBlockTy, - /*dynamicSelfType=*/CanType()); + /*dynamicSelfType=*/CanType(), + /*global actor=*/CanType()); // Build it if necessary. if (thunk->empty()) { @@ -975,7 +976,8 @@ SILGenFunction::emitBlockToFunc(SILLocation loc, auto thunk = SGM.getOrCreateReabstractionThunk(thunkTy, loweredBlockTy, loweredFuncUnsubstTy, - /*dynamicSelfType=*/CanType()); + /*dynamicSelfType=*/CanType(), + /*global actor=*/CanType()); // Build it if necessary. if (thunk->empty()) { diff --git a/lib/SILGen/SILGenPoly.cpp b/lib/SILGen/SILGenPoly.cpp index 242ad44b55f..ad7d0ad7d4e 100644 --- a/lib/SILGen/SILGenPoly.cpp +++ b/lib/SILGen/SILGenPoly.cpp @@ -82,6 +82,7 @@ // //===----------------------------------------------------------------------===// +#include "ExecutorBreadcrumb.h" #include "Initialization.h" #include "LValue.h" #include "RValue.h" @@ -2941,6 +2942,16 @@ static void buildThunkBody(SILGenFunction &SGF, SILLocation loc, assert(!fnType->isPolymorphic()); auto argTypes = fnType->getParameters(); + // If the input is synchronous and global-actor-qualified, and the + // output is asynchronous, hop to the executor expected by the input. + ExecutorBreadcrumb prevExecutor; + if (outputSubstType->isAsync() && !inputSubstType->isAsync()) { + if (Type globalActor = inputSubstType->getGlobalActor()) { + prevExecutor = SGF.emitHopToTargetActor( + loc, ActorIsolation::forGlobalActor(globalActor, false), None); + } + } + // Translate the argument values. Function parameters are // contravariant: we want to switch the direction of transformation // on them by flipping inputOrigType and outputOrigType. @@ -2984,6 +2995,9 @@ static void buildThunkBody(SILGenFunction &SGF, SILLocation loc, // Reabstract the result. SILValue outerResult = resultPlanner.execute(innerResult); + // If we hopped to the target's executor, then we need to hop back. + prevExecutor.emit(SGF, loc); + scope.pop(); SGF.B.createReturn(loc, outerResult); } @@ -3329,11 +3343,20 @@ static ManagedValue createThunk(SILGenFunction &SGF, genericEnv, interfaceSubs, dynamicSelfType); + // An actor-isolated non-async function can be converted to an async function + // by inserting a hop to the global actor. + CanType globalActorForThunk; + if (outputSubstType->isAsync() + && !inputSubstType->isAsync()) { + globalActorForThunk = CanType(inputSubstType->getGlobalActor()); + } + auto thunk = SGF.SGM.getOrCreateReabstractionThunk( thunkType, sourceType, toType, - dynamicSelfType); + dynamicSelfType, + globalActorForThunk); // Build it if necessary. if (thunk->empty()) { @@ -3557,7 +3580,7 @@ SILGenFunction::createWithoutActuallyEscapingClosure( dynamicSelfType); auto *thunk = SGM.getOrCreateReabstractionThunk( - thunkType, noEscapingFnTy, escapingFnTy, dynamicSelfType); + thunkType, noEscapingFnTy, escapingFnTy, dynamicSelfType, CanType()); if (thunk->empty()) { thunk->setWithoutActuallyEscapingThunk(); @@ -3661,7 +3684,7 @@ ManagedValue SILGenFunction::getThunkedAutoDiffLinearMap( // Otherwise, it is just a normal reabstraction thunk. else { name = mangler.mangleReabstractionThunkHelper( - thunkType, fromInterfaceType, toInterfaceType, Type(), + thunkType, fromInterfaceType, toInterfaceType, Type(), Type(), getModule().getSwiftModule()); } diff --git a/lib/SILGen/SILGenThunk.cpp b/lib/SILGen/SILGenThunk.cpp index 07474b0b697..040ca6fdc1a 100644 --- a/lib/SILGen/SILGenThunk.cpp +++ b/lib/SILGen/SILGenThunk.cpp @@ -28,6 +28,7 @@ #include "swift/AST/DiagnosticsSIL.h" #include "swift/AST/FileUnit.h" #include "swift/AST/ForeignAsyncConvention.h" +#include "swift/SIL/FormalLinkage.h" #include "swift/AST/GenericEnvironment.h" #include "swift/SIL/PrettyStackTrace.h" #include "swift/SIL/SILArgument.h" @@ -429,7 +430,8 @@ SILFunction *SILGenModule:: getOrCreateReabstractionThunk(CanSILFunctionType thunkType, CanSILFunctionType fromType, CanSILFunctionType toType, - CanType dynamicSelfType) { + CanType dynamicSelfType, + CanType fromGlobalActorBound) { // The reference to the thunk is likely @noescape, but declarations are always // escaping. auto thunkDeclType = @@ -445,18 +447,31 @@ getOrCreateReabstractionThunk(CanSILFunctionType thunkType, if (dynamicSelfType) dynamicSelfInterfaceType = dynamicSelfType->mapTypeOutOfContext() ->getCanonicalType(); + if (fromGlobalActorBound) + fromGlobalActorBound = fromGlobalActorBound->mapTypeOutOfContext() + ->getCanonicalType(); Mangle::ASTMangler NewMangler; std::string name = NewMangler.mangleReabstractionThunkHelper(thunkType, fromInterfaceType, toInterfaceType, dynamicSelfInterfaceType, + fromGlobalActorBound, M.getSwiftModule()); auto loc = RegularLocation::getAutoGeneratedLocation(); + + // The thunk that converts an actor-constrained, non-async function to an + // async function is not serializable if the actor's visibility precludes it. + auto serializable = IsSerializable; + if (fromGlobalActorBound) { + auto globalActorLinkage = getTypeLinkage(fromGlobalActorBound); + serializable = globalActorLinkage >= FormalLinkage::PublicNonUnique + ? IsSerializable : IsNotSerialized; + } SILGenFunctionBuilder builder(*this); return builder.getOrCreateSharedFunction( - loc, name, thunkDeclType, IsBare, IsTransparent, IsSerializable, + loc, name, thunkDeclType, IsBare, IsTransparent, serializable, ProfileCounter(), IsReabstractionThunk, IsNotDynamic); } diff --git a/lib/SILOptimizer/Differentiation/Thunk.cpp b/lib/SILOptimizer/Differentiation/Thunk.cpp index b829502deae..4eb71136ca7 100644 --- a/lib/SILOptimizer/Differentiation/Thunk.cpp +++ b/lib/SILOptimizer/Differentiation/Thunk.cpp @@ -324,7 +324,7 @@ SILFunction *getOrCreateReabstractionThunk(SILOptFunctionBuilder &fb, Mangle::ASTMangler mangler; std::string name = mangler.mangleReabstractionThunkHelper( - thunkType, fromInterfaceType, toInterfaceType, Type(), + thunkType, fromInterfaceType, toInterfaceType, Type(), Type(), module.getSwiftModule()); auto *thunk = fb.getOrCreateSharedFunction( diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 157373328b1..20000942aae 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -2114,8 +2114,8 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2, auto result = matchTypes(func1->getGlobalActor(), func2->getGlobalActor(), ConstraintKind::Equal, subflags, locator); if (result == SolutionKind::Error) return getTypeMatchFailure(locator); - } else if (func1->getGlobalActor()) { - // Cannot remove a global actor. + } else if (func1->getGlobalActor() && !func2->isAsync()) { + // Cannot remove a global actor from a synchronous function. if (!shouldAttemptFixes()) return getTypeMatchFailure(locator); diff --git a/test/Concurrency/global_actor_function_types.swift b/test/Concurrency/global_actor_function_types.swift index bf7286aa412..4172598edc2 100644 --- a/test/Concurrency/global_actor_function_types.swift +++ b/test/Concurrency/global_actor_function_types.swift @@ -142,3 +142,10 @@ func testTypesConcurrencyContext() async { _ = await f1() _ = await f2() } + +// Conversion from main-actor-qualified synchronous to unqualified asynchronous. +func test() { + let _: () async -> Int = { @SomeGlobalActor in + onSomeGlobalActor() + } +} diff --git a/test/SILGen/hop_to_executor.swift b/test/SILGen/hop_to_executor.swift index 62807eaa77d..ca2c7eab516 100644 --- a/test/SILGen/hop_to_executor.swift +++ b/test/SILGen/hop_to_executor.swift @@ -100,23 +100,24 @@ func testGlobalActorWithClosure() async { await { () async in }() } +actor MyGenericActor {} + @globalActor struct GenericGlobalActorWithGetter { - static var shared: MyActor { return MyActor() } + static var shared: MyGenericActor { return MyGenericActor() } } // CHECK-LABEL: sil hidden [ossa] @$s4test0A28GenericGlobalActorWithGetteryyYaF : $@convention(thin) @async () -> () { // CHECK: [[MT:%[0-9]+]] = metatype $@thin GenericGlobalActorWithGetter.Type -// CHECK: [[F:%[0-9]+]] = function_ref @$s4test28GenericGlobalActorWithGetterV6sharedAA02MyD0CvgZ : $@convention(method) <τ_0_0> (@thin GenericGlobalActorWithGetter<τ_0_0>.Type) -> @owned MyActor -// CHECK: [[A:%[0-9]+]] = apply [[F]]([[MT]]) : $@convention(method) <τ_0_0> (@thin GenericGlobalActorWithGetter<τ_0_0>.Type) -> @owned MyActor -// CHECK: [[B:%[0-9]+]] = begin_borrow [[A]] : $MyActor -// CHECK: hop_to_executor [[B]] : $MyActor +// CHECK: [[F:%[0-9]+]] = function_ref @$s4test28GenericGlobalActorWithGetterV6sharedAA02MybD0CyxGvgZ +// CHECK: [[A:%[0-9]+]] = apply [[F]]([[MT]]) +// CHECK: [[B:%[0-9]+]] = begin_borrow [[A]] : $MyGenericActor +// CHECK: hop_to_executor [[B]] : $MyGenericActor // CHECK: } // end sil function '$s4test0A28GenericGlobalActorWithGetteryyYaF' @GenericGlobalActorWithGetter func testGenericGlobalActorWithGetter() async { } - actor RedActorImpl { // CHECK-LABEL: sil hidden [ossa] @$s4test12RedActorImplC5helloyySiF : $@convention(method) (Int, @guaranteed RedActorImpl) -> () { // CHECK-NOT: hop_to_executor @@ -262,3 +263,89 @@ extension MyActor { } } } + +func acceptAsyncClosure(_: () async -> Void) { } +func acceptAsyncClosure2(_: (T) async -> T) { } + +public actor MyPublicActor {} + +@globalActor +public struct PublicGlobalActor { + public static var shared: MyPublicActor = MyPublicActor() +} + +@globalActor +private struct PrivateGlobalActor { + static var shared: MyActor = MyActor() +} + +func testGlobalActorClosure() { + // CHECK-LABEL: sil shared [transparent] [reabstraction_thunk] [ossa] @$sIeg_IegH_TR4test11GlobalActorVTU + // CHECK: [[OLD_EXEC:%.*]] = builtin "getCurrentExecutor" + // CHECK: hop_to_executor {{%.*}} : $MyActor + // CHECK: apply %0() + // CHECK: hop_to_executor [[OLD_EXEC]] + let ga: @GlobalActor () -> () = { @GlobalActor in print(5) } + acceptAsyncClosure(ga) + + // CHECK-LABEL: sil shared [transparent] [reabstraction_thunk] [ossa] @$sIeg_IegH_TR4test8RedActorVTU + // CHECK: [[OLD_EXEC:%.*]] = builtin "getCurrentExecutor" + // CHECK: hop_to_executor {{%.*}} : $RedActor + // CHECK: apply %0() + // CHECK: hop_to_executor [[OLD_EXEC]] + let ra: @RedActor () -> () = { @RedActor in print(5) } + acceptAsyncClosure(ra) + + // CHECK-LABEL: sil shared [transparent] [reabstraction_thunk] [ossa] @$sIeg_IegH_TR4test9BlueActorVTU + // CHECK: [[OLD_EXEC:%.*]] = builtin "getCurrentExecutor" + // CHECK: hop_to_executor {{%.*}} : $BlueActor + // CHECK: apply %0() + // CHECK: hop_to_executor [[OLD_EXEC]] + let ba: @BlueActor () -> () = { @BlueActor in print(5) } + acceptAsyncClosure(ba) + + // CHECK-LABEL: sil shared [transparent] [reabstraction_thunk] [ossa] @$sIeg_IegH_TR4test18PrivateGlobalActor{{.*}}VTU + // CHECK: [[OLD_EXEC:%.*]] = builtin "getCurrentExecutor" + // CHECK: hop_to_executor {{%.*}} : $MyActor + // CHECK: apply %0() + // CHECK: hop_to_executor [[OLD_EXEC]] + let pga: @PrivateGlobalActor () -> () = { @PrivateGlobalActor in print(5) } + acceptAsyncClosure(pga) + + // CHECK-LABEL: sil shared [transparent] [reabstraction_thunk] [ossa] @$sIeg_IegH_TR4test17PublicGlobalActorVTU + // CHECK: [[OLD_EXEC:%.*]] = builtin "getCurrentExecutor" + // CHECK: hop_to_executor {{%.*}} : $MyPublicActor + // CHECK: apply %0() + // CHECK: hop_to_executor [[OLD_EXEC]] + let pbga: @PublicGlobalActor () -> () = { @PublicGlobalActor in print(5) } + acceptAsyncClosure(pbga) + + // CHECK-LABEL: sil shared [transparent] [reabstraction_thunk] [ossa] @$sIeg_IegH_TR4test28GenericGlobalActorWithGetterVySiGTU + // CHECK: [[OLD_EXEC:%.*]] = builtin "getCurrentExecutor" + // CHECK: hop_to_executor {{%.*}} : $MyGenericActor + // CHECK: apply %0() + // CHECK: hop_to_executor [[OLD_EXEC]] + let ggai: @GenericGlobalActorWithGetter () -> () + = { @GenericGlobalActorWithGetter in print(5) } + acceptAsyncClosure(ggai) + + // CHECK-LABEL: sil shared [transparent] [reabstraction_thunk] [ossa] @$sIeg_IegH_TR4test28GenericGlobalActorWithGetterVySSGTU + // CHECK: [[OLD_EXEC:%.*]] = builtin "getCurrentExecutor" + // CHECK: hop_to_executor {{%.*}} : $MyGenericActor + // CHECK: apply %0() + // CHECK: hop_to_executor [[OLD_EXEC]] + let ggas: @GenericGlobalActorWithGetter () -> () + = { @GenericGlobalActorWithGetter in print(5) } + acceptAsyncClosure(ggas) +} + +func testGenericGlobalActorClosure(_: T) { + // CHECK-LABEL: sil shared [transparent] [reabstraction_thunk] [ossa] @$sxxIegnr_xxIegHnr_lTR4test28GenericGlobalActorWithGetterVyxGTU + // CHECK: [[OLD_EXEC:%.*]] = builtin "getCurrentExecutor" + // CHECK: hop_to_executor {{%.*}} : $MyGenericActor + // CHECK: apply %2(%0, %1) + // CHECK: hop_to_executor [[OLD_EXEC]] + let ggat: @GenericGlobalActorWithGetter (T) -> T + = { @GenericGlobalActorWithGetter x in x } + acceptAsyncClosure2(ggat) +}