From 769673d0027c3bcd1717f766b478f88e2acce122 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Mon, 7 Apr 2025 17:20:32 -0700 Subject: [PATCH] [concurrency] Implement protocol witness thunking in SILGen for @execution(caller)/@execution(concurrent). This involved cleaning up and generalizing the work from f245389bb3bffcb14eeca30b185a30dc8d4037fe. I followed the same approach: hide the implicit parameter while we run things through translateArgument and friends and then put it back in manually. As an additional benefit, I think I found a good place to put FunctionIsolation onto lowered AnyFunctionTypes that will not cause cycles in the evaluator since it is done in TypeLowering. rdar://148785846 (cherry picked from commit 04b845cc9712d75a77a4aa6958340c7b436171c9) --- lib/SILGen/SILGenFunction.h | 13 +- lib/SILGen/SILGenPoly.cpp | 204 ++++++++++++------ ...{silgen.swift => conversions_silgen.swift} | 0 .../attr_execution/protocols_silgen.swift | 129 +++++++++++ 4 files changed, 278 insertions(+), 68 deletions(-) rename test/Concurrency/attr_execution/{silgen.swift => conversions_silgen.swift} (100%) create mode 100644 test/Concurrency/attr_execution/protocols_silgen.swift diff --git a/lib/SILGen/SILGenFunction.h b/lib/SILGen/SILGenFunction.h index 4fa83c5e326ed..ce11a54719c99 100644 --- a/lib/SILGen/SILGenFunction.h +++ b/lib/SILGen/SILGenFunction.h @@ -2603,8 +2603,17 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction enum class ThunkGenFlag { None, - ConvertingToNonIsolatedCaller, - ConvertingFromNonIsolatedCaller, + + /// Set if the thunk has an implicit isolated parameter. + /// + /// The implication is that we shouldn't forward that parameter into the + /// callee as a normal parameter (if the callee has an implicit param, we + /// handle it through a different code path). + ThunkHasImplicitIsolatedParam = 0x1, + + /// Set if the callee has an implicit isolated parameter that we need to + /// find the appropriate value for when we call it from the thunk. + CalleeHasImplicitIsolatedParam = 0x2, }; using ThunkGenOptions = OptionSet; diff --git a/lib/SILGen/SILGenPoly.cpp b/lib/SILGen/SILGenPoly.cpp index b7a4ca4d442a2..409894e588202 100644 --- a/lib/SILGen/SILGenPoly.cpp +++ b/lib/SILGen/SILGenPoly.cpp @@ -1025,10 +1025,9 @@ void SILGenFunction::collectThunkParams( auto functionArgument = B.createInputFunctionArgument(inContextParamTy, loc); - // If we are told to not propagate the isolated parameter and this is the - // implicit leading/isolated parameter, continue. - if (options.contains(ThunkGenFlag::ConvertingToNonIsolatedCaller) && - param.hasOption(SILParameterInfo::ImplicitLeading) && + // If our thunk has an implicit param and we are being asked to forward it, + // to the callee, skip it. We are going to handle it especially later. + if (param.hasOption(SILParameterInfo::ImplicitLeading) && param.hasOption(SILParameterInfo::Isolated)) continue; params.push_back(functionArgument); @@ -2925,8 +2924,11 @@ forwardFunctionArguments(SILGenFunction &SGF, SILLocation loc, SmallVectorImpl &forwardedArgs, SILGenFunction::ThunkGenOptions options = {}) { auto argTypes = fTy->getParameters(); + + // If our callee has an implicit parameter, we have already inserted it, so + // drop it from argTypes. if (options.contains( - SILGenFunction::ThunkGenFlag::ConvertingFromNonIsolatedCaller)) { + SILGenFunction::ThunkGenFlag::CalleeHasImplicitIsolatedParam)) { argTypes = argTypes.drop_front(); } @@ -5453,16 +5455,11 @@ static void buildThunkBody(SILGenFunction &SGF, SILLocation loc, // isolated parameter preventing us from having to memcpy over the array. if (outputSubstType->isAsync()) { if (outputSubstType->getIsolation().getKind() == - FunctionTypeIsolation::Kind::NonIsolatedCaller && - inputSubstType->getIsolation().getKind() != - FunctionTypeIsolation::Kind::NonIsolatedCaller) - options |= ThunkGenFlag::ConvertingToNonIsolatedCaller; - - if (outputSubstType->getIsolation().getKind() != - FunctionTypeIsolation::Kind::NonIsolatedCaller && - inputSubstType->getIsolation().getKind() == - FunctionTypeIsolation::Kind::NonIsolatedCaller) - options |= ThunkGenFlag::ConvertingFromNonIsolatedCaller; + FunctionTypeIsolation::Kind::NonIsolatedCaller) + options |= ThunkGenFlag::ThunkHasImplicitIsolatedParam; + if (inputSubstType->getIsolation().getKind() == + FunctionTypeIsolation::Kind::NonIsolatedCaller) + options |= ThunkGenFlag::CalleeHasImplicitIsolatedParam; } SmallVector params; @@ -5485,14 +5482,16 @@ static void buildThunkBody(SILGenFunction &SGF, SILLocation loc, outputErasedIsolation = params.pop_back_val(); } - if (!SGF.F.maybeGetIsolatedArgument() && argTypes.size() && + if (argTypes.size() && argTypes.front().hasOption(SILParameterInfo::Isolated) && argTypes.front().hasOption(SILParameterInfo::ImplicitLeading)) - options |= ThunkGenFlag::ConvertingFromNonIsolatedCaller; + options |= ThunkGenFlag::CalleeHasImplicitIsolatedParam; - // If we are converting to nonisolated caller, we are going to have an extra - // parameter in our argTypes that we need to drop. - if (options.contains(ThunkGenFlag::ConvertingFromNonIsolatedCaller)) + // If we are converting from a nonisolated caller, we are going to have an + // extra parameter in our argTypes that we need to drop. We are going to + // handle it separately later so that TranslateArguments does not have to know + // anything about it. + if (options.contains(ThunkGenFlag::CalleeHasImplicitIsolatedParam)) argTypes = argTypes.drop_front(); // We may need to establish the right executor for the input function. @@ -5597,7 +5596,7 @@ static void buildThunkBody(SILGenFunction &SGF, SILLocation loc, // If we are thunking a nonisolated caller to nonisolated or global actor, we // need to load the actor. - if (options.contains(ThunkGenFlag::ConvertingFromNonIsolatedCaller)) { + if (options.contains(ThunkGenFlag::CalleeHasImplicitIsolatedParam)) { auto outputIsolation = outputSubstType->getIsolation(); switch (outputIsolation.getKind()) { case FunctionTypeIsolation::Kind::NonIsolated: @@ -7264,11 +7263,60 @@ void SILGenFunction::emitProtocolWitness( FullExpr scope(Cleanups, cleanupLoc); FormalEvaluationScope formalEvalScope(*this); + // Grab the type of our thunk. auto thunkTy = F.getLoweredFunctionType(); + // Then get the type of the witness. + auto witnessKind = getWitnessDispatchKind(witness, isSelfConformance); + auto witnessInfo = getConstantInfo(getTypeExpansionContext(), witness); + CanAnyFunctionType witnessSubstTy = witnessInfo.LoweredType; + if (auto genericFnType = dyn_cast(witnessSubstTy)) { + witnessSubstTy = cast( + genericFnType->substGenericArgs(witnessSubs)->getCanonicalType()); + } + + assert(!witnessSubstTy->hasError()); + + if (auto genericFnType = dyn_cast(reqtSubstTy)) { + auto forwardingSubs = F.getForwardingSubstitutionMap(); + reqtSubstTy = cast( + genericFnType->substGenericArgs(forwardingSubs)->getCanonicalType()); + } else { + reqtSubstTy = cast( + F.mapTypeIntoContext(reqtSubstTy)->getCanonicalType()); + } + + assert(!reqtSubstTy->hasError()); + + // Get the lowered type of the witness. + auto origWitnessFTy = getWitnessFunctionType(getTypeExpansionContext(), SGM, + witness, witnessKind); + auto witnessFTy = origWitnessFTy; + if (!witnessSubs.empty()) { + witnessFTy = origWitnessFTy->substGenericArgs(SGM.M, witnessSubs, + getTypeExpansionContext()); + } + + // Now that we have the type information in hand, we can generate the thunk + // body. + + using ThunkGenFlag = SILGenFunction::ThunkGenFlag; + auto options = SILGenFunction::ThunkGenOptions(); + + { + auto thunkIsolatedParam = thunkTy->maybeGetIsolatedParameter(); + if (thunkIsolatedParam && + thunkIsolatedParam->hasOption(SILParameterInfo::ImplicitLeading)) + options |= ThunkGenFlag::ThunkHasImplicitIsolatedParam; + auto witnessIsolatedParam = witnessFTy->maybeGetIsolatedParameter(); + if (witnessIsolatedParam && + witnessIsolatedParam->hasOption(SILParameterInfo::ImplicitLeading)) + options |= ThunkGenFlag::CalleeHasImplicitIsolatedParam; + } + SmallVector origParams; SmallVector thunkIndirectResults; - collectThunkParams(loc, origParams, &thunkIndirectResults); + collectThunkParams(loc, origParams, &thunkIndirectResults, nullptr, options); if (witness.getDecl()->requiresUnavailableDeclABICompatibilityStubs()) emitApplyOfUnavailableCodeReached(); @@ -7305,40 +7353,7 @@ void SILGenFunction::emitProtocolWitness( } } - // Get the type of the witness. - auto witnessKind = getWitnessDispatchKind(witness, isSelfConformance); - auto witnessInfo = getConstantInfo(getTypeExpansionContext(), witness); - CanAnyFunctionType witnessSubstTy = witnessInfo.LoweredType; - if (auto genericFnType = dyn_cast(witnessSubstTy)) { - witnessSubstTy = cast(genericFnType - ->substGenericArgs(witnessSubs) - ->getCanonicalType()); - } - - assert(!witnessSubstTy->hasError()); - - if (auto genericFnType = dyn_cast(reqtSubstTy)) { - auto forwardingSubs = F.getForwardingSubstitutionMap(); - reqtSubstTy = cast(genericFnType - ->substGenericArgs(forwardingSubs) - ->getCanonicalType()); - } else { - reqtSubstTy = cast(F.mapTypeIntoContext(reqtSubstTy) - ->getCanonicalType()); - } - - assert(!reqtSubstTy->hasError()); - - // Get the lowered type of the witness. - auto origWitnessFTy = getWitnessFunctionType(getTypeExpansionContext(), SGM, - witness, witnessKind); - auto witnessFTy = origWitnessFTy; - if (!witnessSubs.empty()) { - witnessFTy = origWitnessFTy->substGenericArgs(SGM.M, witnessSubs, - getTypeExpansionContext()); - } auto witnessUnsubstTy = witnessFTy->getUnsubstitutedType(SGM.M); - auto reqtSubstParams = reqtSubstTy.getParams(); auto witnessSubstParams = witnessSubstTy.getParams(); @@ -7360,8 +7375,8 @@ void SILGenFunction::emitProtocolWitness( // @convention(c) () -> () // . We do this by simply omitting the last params. // TODO: fix this for static C++ methods. - if (witness.getDecl()->getClangDecl() && - isa(witness.getDecl()->getClangDecl())) { + if (isa_and_nonnull( + witness.getDecl()->getClangDecl())) { origParams.pop_back(); reqtSubstParams = reqtSubstParams.drop_back(); ignoreFinalInputOrigParam = true; @@ -7379,15 +7394,19 @@ void SILGenFunction::emitProtocolWitness( // Translate the argument values from the requirement abstraction level to // the substituted signature of the witness. SmallVector witnessParams; + auto witnessParamInfos = witnessUnsubstTy->getParameters(); + + // If we are transforming to a callee with an implicit param, drop the + // implicit param so that we can insert it again later. This ensures + // TranslateArguments does not need to know about this. + if (options.contains(ThunkGenFlag::CalleeHasImplicitIsolatedParam)) + witnessParamInfos = witnessParamInfos.drop_front(); + AbstractionPattern witnessOrigTy(witnessInfo.LoweredType); - TranslateArguments(*this, loc, - origParams, witnessParams, - witnessUnsubstTy, witnessUnsubstTy->getParameters()) - .process(witnessOrigTy, - witnessSubstParams, - reqtOrigTy, - reqtSubstParams, - ignoreFinalInputOrigParam); + TranslateArguments(*this, loc, origParams, witnessParams, witnessUnsubstTy, + witnessParamInfos) + .process(witnessOrigTy, witnessSubstParams, reqtOrigTy, reqtSubstParams, + ignoreFinalInputOrigParam); SILValue witnessFnRef = getWitnessFunctionRef(*this, witness, origWitnessFTy, @@ -7420,8 +7439,61 @@ void SILGenFunction::emitProtocolWitness( } } + // Now that we have translated arguments and inserted our thunk indirect + // parameters... before we forward those arguments, insert the implicit + // leading parameter. + if (options.contains(ThunkGenFlag::CalleeHasImplicitIsolatedParam)) { + auto reqtIsolation = + swift::getActorIsolation(requirement.getAbstractFunctionDecl()); + switch (reqtIsolation) { + case ActorIsolation::Unspecified: + case ActorIsolation::Nonisolated: + case ActorIsolation::NonisolatedUnsafe: + args.push_back(emitNonIsolatedIsolation(loc).getValue()); + break; + case ActorIsolation::Erased: + llvm::report_fatal_error("Found erased actor isolation?!"); + break; + case ActorIsolation::GlobalActor: { + auto globalActor = reqtIsolation.getGlobalActor()->getCanonicalType(); + args.push_back(emitGlobalActorIsolation(loc, globalActor).getValue()); + break; + } + case ActorIsolation::ActorInstance: + case ActorIsolation::CallerIsolationInheriting: { + auto witnessIsolation = + swift::getActorIsolation(witness.getAbstractFunctionDecl()); + switch (witnessIsolation) { + case ActorIsolation::Unspecified: + case ActorIsolation::Nonisolated: + case ActorIsolation::NonisolatedUnsafe: + args.push_back(emitNonIsolatedIsolation(loc).getValue()); + break; + case ActorIsolation::Erased: + llvm::report_fatal_error("Found erased actor isolation?!"); + break; + case ActorIsolation::GlobalActor: { + auto globalActor = + witnessIsolation.getGlobalActor()->getCanonicalType(); + args.push_back(emitGlobalActorIsolation(loc, globalActor).getValue()); + break; + } + case ActorIsolation::ActorInstance: + case ActorIsolation::CallerIsolationInheriting: { + auto isolatedArg = F.maybeGetIsolatedArgument(); + assert(isolatedArg); + args.push_back(isolatedArg); + break; + } + } + break; + } + } + } + // - the rest of the arguments - forwardFunctionArguments(*this, loc, witnessFTy, witnessParams, args); + forwardFunctionArguments(*this, loc, witnessFTy, witnessParams, args, + options); // Perform the call. SILType witnessSILTy = SILType::getPrimitiveObjectType(witnessFTy); diff --git a/test/Concurrency/attr_execution/silgen.swift b/test/Concurrency/attr_execution/conversions_silgen.swift similarity index 100% rename from test/Concurrency/attr_execution/silgen.swift rename to test/Concurrency/attr_execution/conversions_silgen.swift diff --git a/test/Concurrency/attr_execution/protocols_silgen.swift b/test/Concurrency/attr_execution/protocols_silgen.swift new file mode 100644 index 0000000000000..78e81d36d14ef --- /dev/null +++ b/test/Concurrency/attr_execution/protocols_silgen.swift @@ -0,0 +1,129 @@ +// RUN: %target-swift-emit-silgen %s -module-name attr_execution_silgen -target %target-swift-5.1-abi-triple -enable-experimental-feature ExecutionAttribute -DSWIFT_FIVE | %FileCheck -check-prefix CHECK -check-prefix FIVE %s +// RUN: %target-swift-emit-silgen %s -swift-version 6 -module-name attr_execution_silgen -target %target-swift-5.1-abi-triple -enable-experimental-feature ExecutionAttribute | %FileCheck -check-prefix CHECK -check-prefix SIX %s + +// We codegen slightly differently for swift 5 vs swift 6, so we need to check +// both. + +// REQUIRES: asserts +// REQUIRES: concurrency +// REQUIRES: swift_feature_ExecutionAttribute + +protocol P { + @execution(caller) func callerTest() async + @execution(concurrent) func concurrentTest() async + @MainActor func mainActorTest() async +} + +struct AllDefault : P { + // CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s21attr_execution_silgen10AllDefaultVAA1PA2aDP10callerTestyyYaFTW : $@convention(witness_method: P) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional, @in_guaranteed AllDefault) -> () { + // CHECK: bb0([[ACTOR:%.*]] : @guaranteed $Optional, [[SELF:%.*]] : $*AllDefault): + // CHECK: [[LOAD:%.*]] = load [trivial] [[SELF]] + // CHECK: [[FUNC:%.*]] = function_ref @$s21attr_execution_silgen10AllDefaultV10callerTestyyYaF : $@convention(method) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional, AllDefault) -> () + // CHECK: apply [[FUNC]]([[ACTOR]], [[LOAD]]) + // CHECK: } // end sil function '$s21attr_execution_silgen10AllDefaultVAA1PA2aDP10callerTestyyYaFTW' + func callerTest() async {} + + // CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s21attr_execution_silgen10AllDefaultVAA1PA2aDP14concurrentTestyyYaFTW : $@convention(witness_method: P) @async (@in_guaranteed AllDefault) -> () { + // CHECK: bb0([[SELF:%.*]] : $*AllDefault): + // CHECK: [[LOAD:%.*]] = load [trivial] [[SELF]] + // CHECK: [[FUNC:%.*]] = function_ref @$s21attr_execution_silgen10AllDefaultV14concurrentTestyyYaF : $@convention(method) @async (AllDefault) -> () + // CHECK: apply [[FUNC]]([[LOAD]]) + // CHECK: } // end sil function '$s21attr_execution_silgen10AllDefaultVAA1PA2aDP14concurrentTestyyYaFTW' + func concurrentTest() async {} + + // CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s21attr_execution_silgen10AllDefaultVAA1PA2aDP13mainActorTestyyYaFTW : $@convention(witness_method: P) @async (@in_guaranteed AllDefault) -> () { + // CHECK: bb0([[SELF:%.*]] : $*AllDefault): + // CHECK: [[LOAD:%.*]] = load [trivial] [[SELF]] + // CHECK: [[FUNC:%.*]] = function_ref @$s21attr_execution_silgen10AllDefaultV13mainActorTestyyYaF : $@convention(method) @async (AllDefault) -> () + // CHECK: apply [[FUNC]]([[LOAD]]) + // CHECK: } // end sil function '$s21attr_execution_silgen10AllDefaultVAA1PA2aDP13mainActorTestyyYaFTW' + func mainActorTest() async {} +} + +struct AllCaller : P { + // CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s21attr_execution_silgen9AllCallerVAA1PA2aDP10callerTestyyYaFTW : $@convention(witness_method: P) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional, @in_guaranteed AllCaller) -> () { + // CHECK: bb0([[ACTOR:%.*]] : @guaranteed $Optional, [[SELF:%.*]] : $*AllCaller): + // CHECK: [[LOAD:%.*]] = load [trivial] [[SELF]] + // CHECK: [[FUNC:%.*]] = function_ref @$s21attr_execution_silgen9AllCallerV10callerTestyyYaF : $@convention(method) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional, AllCaller) -> () + // CHECK: apply [[FUNC]]([[ACTOR]], [[LOAD]]) + // CHECK: } // end sil function '$s21attr_execution_silgen9AllCallerVAA1PA2aDP10callerTestyyYaFTW' + @execution(caller) func callerTest() async {} + + // CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s21attr_execution_silgen9AllCallerVAA1PA2aDP14concurrentTestyyYaFTW : $@convention(witness_method: P) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional, @in_guaranteed AllCaller) -> () { + // CHECK: bb0([[ACTOR:%.*]] : @guaranteed $Optional, [[SELF:%.*]] : $*AllCaller): + // CHECK: [[LOAD:%.*]] = load [trivial] [[SELF]] + // CHECK: [[FUNC:%.*]] = function_ref @$s21attr_execution_silgen9AllCallerV14concurrentTestyyYaF : $@convention(method) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional, AllCaller) -> () + // CHECK: [[NIL:%.*]] = enum $Optional, #Optional.none!enumelt + // CHECK: apply [[FUNC]]([[NIL]], [[LOAD]]) + // CHECK: } // end sil function '$s21attr_execution_silgen9AllCallerVAA1PA2aDP14concurrentTestyyYaFTW' + @execution(caller) func concurrentTest() async {} + + // CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s21attr_execution_silgen9AllCallerVAA1PA2aDP13mainActorTestyyYaFTW : $@convention(witness_method: P) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional, @in_guaranteed AllCaller) -> () { + // CHECK: bb0({{%.*}} : @guaranteed $Optional, [[SELF:%.*]] : $*AllCaller): + // CHECK: [[LOAD:%.*]] = load [trivial] [[SELF]] + // CHECK: [[FUNC:%.*]] = function_ref @$s21attr_execution_silgen9AllCallerV13mainActorTestyyYaF : $@convention(method) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional, AllCaller) -> () + // CHECK: [[MAIN_ACTOR:%.*]] = apply {{%.*}}({{%.*}}) : $@convention(method) (@thick MainActor.Type) -> @owned MainActor + // CHECK: [[EXIS_MAIN_ACTOR:%.*]] = init_existential_ref [[MAIN_ACTOR]] + // CHECK: [[OPT_MAIN_ACTOR:%.*]] = enum $Optional, #Optional.some!enumelt, [[EXIS_MAIN_ACTOR]] + // CHECK: apply [[FUNC]]([[OPT_MAIN_ACTOR]], [[LOAD]]) + // CHECK: } // end sil function '$s21attr_execution_silgen9AllCallerVAA1PA2aDP13mainActorTestyyYaFTW' + @execution(caller) func mainActorTest() async {} +} + +struct AllConcurrent : P { + // TODO: This seems wrong. We need to have our thunk have the implicit + // isolated parameter from an ABI perspective. + // + // CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s21attr_execution_silgen13AllConcurrentVAA1PA2aDP10callerTestyyYaFTW : $@convention(witness_method: P) @async (@in_guaranteed AllConcurrent) -> () { + // CHECK: bb0([[SELF:%.*]] : + // CHECK: [[LOAD:%.*]] = load [trivial] [[SELF]] + // CHECK: [[FUNC:%.*]] = function_ref @$s21attr_execution_silgen13AllConcurrentV10callerTestyyYaF : $@convention(method) @async (AllConcurrent) -> () + // CHECK: apply [[FUNC]]([[LOAD]]) + // CHECK: } // end sil function '$s21attr_execution_silgen13AllConcurrentVAA1PA2aDP10callerTestyyYaFTW' + @execution(concurrent) func callerTest() async {} + + // CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s21attr_execution_silgen13AllConcurrentVAA1PA2aDP14concurrentTestyyYaFTW : $@convention(witness_method: P) @async (@in_guaranteed AllConcurrent) -> () { + // CHECK: bb0([[SELF:%.*]] : + // CHECK: [[LOAD:%.*]] = load [trivial] [[SELF]] + // CHECK: [[FUNC:%.*]] = function_ref @$s21attr_execution_silgen13AllConcurrentV14concurrentTestyyYaF : $@convention(method) @async (AllConcurrent) -> () + // CHECK: apply [[FUNC]]([[LOAD]]) + // CHECK: } // end sil function '$s21attr_execution_silgen13AllConcurrentVAA1PA2aDP14concurrentTestyyYaFTW' + @execution(concurrent) func concurrentTest() async {} + + // CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s21attr_execution_silgen13AllConcurrentVAA1PA2aDP13mainActorTestyyYaFTW : $@convention(witness_method: P) @async (@in_guaranteed AllConcurrent) -> () { + // CHECK: bb0([[SELF:%.*]] : + // CHECK: [[LOAD:%.*]] = load [trivial] [[SELF]] + // CHECK: [[FUNC:%.*]] = function_ref @$s21attr_execution_silgen13AllConcurrentV13mainActorTestyyYaF : $@convention(method) @async (AllConcurrent) -> () + // CHECK: apply [[FUNC]]([[LOAD]]) + // CHECK: } // end sil function '$s21attr_execution_silgen13AllConcurrentVAA1PA2aDP13mainActorTestyyYaFTW' + @execution(concurrent) func mainActorTest() async {} +} + +struct AllMainActor : P { + // TODO: This is incorrect from an ABI perspective. The witness needs to have + // the implicit isolated parameter. + // + // CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s21attr_execution_silgen12AllMainActorVAA1PA2aDP10callerTestyyYaFTW : $@convention(witness_method: P) @async (@in_guaranteed AllMainActor) -> () { + // CHECK: bb0([[SELF:%.*]] : + // CHECK: [[LOAD:%.*]] = load [trivial] [[SELF]] + // CHECK: [[FUNC:%.*]] = function_ref @$s21attr_execution_silgen12AllMainActorV10callerTestyyYaF : $@convention(method) @async (AllMainActor) -> () + // CHECK: apply [[FUNC]]([[LOAD]]) + // CHECK: } // end sil function '$s21attr_execution_silgen12AllMainActorVAA1PA2aDP10callerTestyyYaFTW' + @MainActor func callerTest() async {} + + // CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s21attr_execution_silgen12AllMainActorVAA1PA2aDP14concurrentTestyyYaFTW : $@convention(witness_method: P) @async (@in_guaranteed AllMainActor) -> () { + // CHECK: bb0([[SELF:%.*]] : + // CHECK: [[LOAD:%.*]] = load [trivial] [[SELF]] + // CHECK: [[FUNC:%.*]] = function_ref @$s21attr_execution_silgen12AllMainActorV14concurrentTestyyYaF : $@convention(method) @async (AllMainActor) -> () + // CHECK: apply [[FUNC]]([[LOAD]]) + // CHECK: } // end sil function '$s21attr_execution_silgen12AllMainActorVAA1PA2aDP14concurrentTestyyYaFTW' + @MainActor func concurrentTest() async {} + + // CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s21attr_execution_silgen12AllMainActorVAA1PA2aDP04mainF4TestyyYaFTW : $@convention(witness_method: P) @async (@in_guaranteed AllMainActor) -> () { + // CHECK: bb0([[SELF:%.*]] : + // CHECK: [[LOAD:%.*]] = load [trivial] [[SELF]] + // CHECK: [[FUNC:%.*]] = function_ref @$s21attr_execution_silgen12AllMainActorV04mainF4TestyyYaF : $@convention(method) @async (AllMainActor) -> () + // CHECK: apply [[FUNC]]([[LOAD]]) + // CHECK: } // end sil function '$s21attr_execution_silgen12AllMainActorVAA1PA2aDP04mainF4TestyyYaFTW' + @MainActor func mainActorTest() async {} +}