@@ -2718,6 +2718,28 @@ class DelayedArgument {
2718
2718
return LV ().Loc ;
2719
2719
}
2720
2720
2721
+ bool isDefaultArg () const {
2722
+ return Kind == DefaultArgument;
2723
+ }
2724
+
2725
+ SILLocation getDefaultArgLoc () const {
2726
+ assert (isDefaultArg ());
2727
+ auto storage = Value.get <DefaultArgumentStorage>(Kind);
2728
+ return storage.loc ;
2729
+ }
2730
+
2731
+ llvm::Optional<ActorIsolation> getIsolation () const {
2732
+ if (!isDefaultArg ())
2733
+ return llvm::None;
2734
+
2735
+ auto storage = Value.get <DefaultArgumentStorage>(Kind);
2736
+ if (!storage.implicitlyAsync )
2737
+ return llvm::None;
2738
+
2739
+ auto callee = storage.defaultArgsOwner .getDecl ();
2740
+ return getActorIsolation (callee);
2741
+ }
2742
+
2721
2743
void emit (SILGenFunction &SGF, SmallVectorImpl<ManagedValue> &args,
2722
2744
size_t &argIndex) {
2723
2745
switch (Kind) {
@@ -2943,6 +2965,31 @@ static void emitDelayedArguments(SILGenFunction &SGF,
2943
2965
MutableArrayRef<SmallVector<ManagedValue, 4 >> args) {
2944
2966
assert (!delayedArgs.empty ());
2945
2967
2968
+ // If any of the delayed arguments are isolated default arguments,
2969
+ // argument evaluation happens in the following order:
2970
+ //
2971
+ // 1. Left-to-right evalution of explicit r-value arguments
2972
+ // 2. Left-to-right evaluation of formal access arguments
2973
+ // 3. Hop to the callee's isolation domain
2974
+ // 4. Left-to-right evaluation of default arguments
2975
+
2976
+ // So, if any delayed arguments are isolated, all default arguments
2977
+ // are collected during the first pass over the delayed arguments,
2978
+ // and emitted separately after a hop to the callee's isolation domain.
2979
+
2980
+ llvm::Optional<ActorIsolation> defaultArgIsolation;
2981
+ for (auto &arg : delayedArgs) {
2982
+ if (auto isolation = arg.getIsolation ()) {
2983
+ defaultArgIsolation = isolation;
2984
+ break ;
2985
+ }
2986
+ }
2987
+
2988
+ SmallVector<std::tuple<
2989
+ /* delayedArgIt*/ decltype (delayedArgs)::iterator,
2990
+ /* siteArgsIt*/ decltype (args)::iterator,
2991
+ /* index*/ size_t >, 2 > isolatedArgs;
2992
+
2946
2993
SmallVector<std::pair<SILValue, SILLocation>, 4 > emittedInoutArgs;
2947
2994
auto delayedNext = delayedArgs.begin ();
2948
2995
@@ -2951,7 +2998,8 @@ static void emitDelayedArguments(SILGenFunction &SGF,
2951
2998
// wherever there's a delayed argument to insert.
2952
2999
//
2953
3000
// Note that this also begins the formal accesses in evaluation order.
2954
- for (auto &siteArgs : args) {
3001
+ for (auto argsIt = args.begin (); argsIt != args.end (); ++argsIt) {
3002
+ auto &siteArgs = *argsIt;
2955
3003
// NB: siteArgs.size() may change during iteration
2956
3004
for (size_t i = 0 ; i < siteArgs.size (); ) {
2957
3005
auto &siteArg = siteArgs[i];
@@ -2964,6 +3012,15 @@ static void emitDelayedArguments(SILGenFunction &SGF,
2964
3012
assert (delayedNext != delayedArgs.end ());
2965
3013
auto &delayedArg = *delayedNext;
2966
3014
3015
+ if (defaultArgIsolation && delayedArg.isDefaultArg ()) {
3016
+ isolatedArgs.push_back (std::make_tuple (delayedNext, argsIt, i));
3017
+ if (++delayedNext == delayedArgs.end ()) {
3018
+ goto done;
3019
+ } else {
3020
+ continue ;
3021
+ }
3022
+ }
3023
+
2967
3024
// Emit the delayed argument and replace it in the arguments array.
2968
3025
delayedArg.emit (SGF, siteArgs, i);
2969
3026
@@ -2984,6 +3041,45 @@ static void emitDelayedArguments(SILGenFunction &SGF,
2984
3041
2985
3042
done:
2986
3043
3044
+ if (defaultArgIsolation) {
3045
+ assert (SGF.F .isAsync ());
3046
+ assert (!isolatedArgs.empty ());
3047
+
3048
+ auto &firstArg = *std::get<0 >(isolatedArgs[0 ]);
3049
+ auto loc = firstArg.getDefaultArgLoc ();
3050
+
3051
+ SILValue executor;
3052
+ switch (*defaultArgIsolation) {
3053
+ case ActorIsolation::GlobalActor:
3054
+ case ActorIsolation::GlobalActorUnsafe:
3055
+ executor = SGF.emitLoadGlobalActorExecutor (
3056
+ defaultArgIsolation->getGlobalActor ());
3057
+ break ;
3058
+
3059
+ case ActorIsolation::ActorInstance:
3060
+ llvm_unreachable (" default arg cannot be actor instance isolated" );
3061
+
3062
+ case ActorIsolation::Unspecified:
3063
+ case ActorIsolation::Nonisolated:
3064
+ case ActorIsolation::NonisolatedUnsafe:
3065
+ llvm_unreachable (" Not isolated" );
3066
+ }
3067
+
3068
+ // Hop to the target isolation domain once to evaluate all
3069
+ // default arguments.
3070
+ SGF.emitHopToTargetExecutor (loc, executor);
3071
+
3072
+ size_t argsEmitted = 0 ;
3073
+ for (auto &isolatedArg : isolatedArgs) {
3074
+ auto &delayedArg = *std::get<0 >(isolatedArg);
3075
+ auto &siteArgs = *std::get<1 >(isolatedArg);
3076
+ auto argIndex = std::get<2 >(isolatedArg) + argsEmitted;
3077
+ auto origIndex = argIndex;
3078
+ delayedArg.emit (SGF, siteArgs, argIndex);
3079
+ argsEmitted += (argIndex - origIndex);
3080
+ }
3081
+ }
3082
+
2987
3083
// Check to see if we have multiple inout arguments which obviously
2988
3084
// alias. Note that we could do this in a later SILDiagnostics pass
2989
3085
// as well: this would be stronger (more equivalences exposed) but
0 commit comments