@@ -2695,6 +2695,28 @@ class DelayedArgument {
2695
2695
return LV ().Loc ;
2696
2696
}
2697
2697
2698
+ bool isDefaultArg () const {
2699
+ return Kind == DefaultArgument;
2700
+ }
2701
+
2702
+ SILLocation getDefaultArgLoc () const {
2703
+ assert (isDefaultArg ());
2704
+ auto storage = Value.get <DefaultArgumentStorage>(Kind);
2705
+ return storage.loc ;
2706
+ }
2707
+
2708
+ llvm::Optional<ActorIsolation> getIsolation () const {
2709
+ if (!isDefaultArg ())
2710
+ return llvm::None;
2711
+
2712
+ auto storage = Value.get <DefaultArgumentStorage>(Kind);
2713
+ if (!storage.implicitlyAsync )
2714
+ return llvm::None;
2715
+
2716
+ auto callee = storage.defaultArgsOwner .getDecl ();
2717
+ return getActorIsolation (callee);
2718
+ }
2719
+
2698
2720
void emit (SILGenFunction &SGF, SmallVectorImpl<ManagedValue> &args,
2699
2721
size_t &argIndex) {
2700
2722
switch (Kind) {
@@ -2920,6 +2942,31 @@ static void emitDelayedArguments(SILGenFunction &SGF,
2920
2942
MutableArrayRef<SmallVector<ManagedValue, 4 >> args) {
2921
2943
assert (!delayedArgs.empty ());
2922
2944
2945
+ // If any of the delayed arguments are isolated default arguments,
2946
+ // argument evaluation happens in the following order:
2947
+ //
2948
+ // 1. Left-to-right evalution of explicit r-value arguments
2949
+ // 2. Left-to-right evaluation of formal access arguments
2950
+ // 3. Hop to the callee's isolation domain
2951
+ // 4. Left-to-right evaluation of default arguments
2952
+
2953
+ // So, if any delayed arguments are isolated, all default arguments
2954
+ // are collected during the first pass over the delayed arguments,
2955
+ // and emitted separately after a hop to the callee's isolation domain.
2956
+
2957
+ llvm::Optional<ActorIsolation> defaultArgIsolation;
2958
+ for (auto &arg : delayedArgs) {
2959
+ if (auto isolation = arg.getIsolation ()) {
2960
+ defaultArgIsolation = isolation;
2961
+ break ;
2962
+ }
2963
+ }
2964
+
2965
+ SmallVector<std::tuple<
2966
+ /* delayedArgIt*/ decltype (delayedArgs)::iterator,
2967
+ /* siteArgsIt*/ decltype (args)::iterator,
2968
+ /* index*/ size_t >, 2 > isolatedArgs;
2969
+
2923
2970
SmallVector<std::pair<SILValue, SILLocation>, 4 > emittedInoutArgs;
2924
2971
auto delayedNext = delayedArgs.begin ();
2925
2972
@@ -2928,7 +2975,8 @@ static void emitDelayedArguments(SILGenFunction &SGF,
2928
2975
// wherever there's a delayed argument to insert.
2929
2976
//
2930
2977
// Note that this also begins the formal accesses in evaluation order.
2931
- for (auto &siteArgs : args) {
2978
+ for (auto argsIt = args.begin (); argsIt != args.end (); ++argsIt) {
2979
+ auto &siteArgs = *argsIt;
2932
2980
// NB: siteArgs.size() may change during iteration
2933
2981
for (size_t i = 0 ; i < siteArgs.size (); ) {
2934
2982
auto &siteArg = siteArgs[i];
@@ -2941,6 +2989,15 @@ static void emitDelayedArguments(SILGenFunction &SGF,
2941
2989
assert (delayedNext != delayedArgs.end ());
2942
2990
auto &delayedArg = *delayedNext;
2943
2991
2992
+ if (defaultArgIsolation && delayedArg.isDefaultArg ()) {
2993
+ isolatedArgs.push_back (std::make_tuple (delayedNext, argsIt, i));
2994
+ if (++delayedNext == delayedArgs.end ()) {
2995
+ goto done;
2996
+ } else {
2997
+ continue ;
2998
+ }
2999
+ }
3000
+
2944
3001
// Emit the delayed argument and replace it in the arguments array.
2945
3002
delayedArg.emit (SGF, siteArgs, i);
2946
3003
@@ -2961,6 +3018,45 @@ static void emitDelayedArguments(SILGenFunction &SGF,
2961
3018
2962
3019
done:
2963
3020
3021
+ if (defaultArgIsolation) {
3022
+ assert (SGF.F .isAsync ());
3023
+ assert (!isolatedArgs.empty ());
3024
+
3025
+ auto &firstArg = *std::get<0 >(isolatedArgs[0 ]);
3026
+ auto loc = firstArg.getDefaultArgLoc ();
3027
+
3028
+ SILValue executor;
3029
+ switch (*defaultArgIsolation) {
3030
+ case ActorIsolation::GlobalActor:
3031
+ case ActorIsolation::GlobalActorUnsafe:
3032
+ executor = SGF.emitLoadGlobalActorExecutor (
3033
+ defaultArgIsolation->getGlobalActor ());
3034
+ break ;
3035
+
3036
+ case ActorIsolation::ActorInstance:
3037
+ llvm_unreachable (" default arg cannot be actor instance isolated" );
3038
+
3039
+ case ActorIsolation::Unspecified:
3040
+ case ActorIsolation::Nonisolated:
3041
+ case ActorIsolation::NonisolatedUnsafe:
3042
+ llvm_unreachable (" Not isolated" );
3043
+ }
3044
+
3045
+ // Hop to the target isolation domain once to evaluate all
3046
+ // default arguments.
3047
+ SGF.emitHopToTargetExecutor (loc, executor);
3048
+
3049
+ size_t argsEmitted = 0 ;
3050
+ for (auto &isolatedArg : isolatedArgs) {
3051
+ auto &delayedArg = *std::get<0 >(isolatedArg);
3052
+ auto &siteArgs = *std::get<1 >(isolatedArg);
3053
+ auto argIndex = std::get<2 >(isolatedArg) + argsEmitted;
3054
+ auto origIndex = argIndex;
3055
+ delayedArg.emit (SGF, siteArgs, argIndex);
3056
+ argsEmitted += (argIndex - origIndex);
3057
+ }
3058
+ }
3059
+
2964
3060
// Check to see if we have multiple inout arguments which obviously
2965
3061
// alias. Note that we could do this in a later SILDiagnostics pass
2966
3062
// as well: this would be stronger (more equivalences exposed) but
0 commit comments