Skip to content

Commit cdb5396

Browse files
committed
[AST] Declare NonIsolatedCaller as kind of FunctionTypeIsolation
This would make sure that async function types marked as `@execution(caller)` have correct isolation. Also defines all of the possible conversions to and from `caller` isolated function types.
1 parent 8c8d573 commit cdb5396

File tree

10 files changed

+92
-4
lines changed

10 files changed

+92
-4
lines changed

include/swift/AST/ExtInfo.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,21 @@ class FunctionTypeIsolation {
6363

6464
/// The function's isolation is statically erased with @isolated(any).
6565
Erased,
66+
67+
/// Inherits isolation from the caller. This is only applicable
68+
/// to asynchronous function types.
69+
///
70+
/// NOTE: The difference in between NonIsolatedCaller and
71+
/// NonIsolated is that NonIsolatedCaller is a strictly
72+
/// weaker form of nonisolation. While both in their bodies cannot
73+
/// access isolated state directly, NonIsolatedCaller functions
74+
/// /are/ allowed to access state isolated to their caller via
75+
/// function arguments since we know that the callee will stay
76+
/// in the caller's isolation domain. In contrast, NonIsolated
77+
/// is strongly nonisolated and is not allowed to access /any/
78+
/// isolated state (even via function parameters) since it is
79+
/// considered safe to run on /any/ actor.
80+
NonIsolatedCaller,
6681
};
6782

6883
static constexpr size_t NumBits = 3; // future-proof this slightly
@@ -87,6 +102,9 @@ class FunctionTypeIsolation {
87102
static FunctionTypeIsolation forErased() {
88103
return { Kind::Erased };
89104
}
105+
static FunctionTypeIsolation forNonIsolatedCaller() {
106+
return { Kind::NonIsolatedCaller };
107+
}
90108

91109
Kind getKind() const { return value.getInt(); }
92110
bool isNonIsolated() const {

lib/AST/ASTMangler.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3285,6 +3285,11 @@ void ASTMangler::appendFunctionSignature(AnyFunctionType *fn,
32853285
if (AllowIsolatedAny)
32863286
appendOperator("YA");
32873287
break;
3288+
3289+
case FunctionTypeIsolation::Kind::NonIsolatedCaller:
3290+
// TODO: We need a special mangling for this to
3291+
// make it distinct from the `@execution(concurrent)`.
3292+
break;
32883293
}
32893294

32903295
if (isRecursedInto && fn->hasSendingResult()) {

lib/AST/ASTPrinter.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6421,6 +6421,10 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
64216421
if (!Options.SuppressIsolatedAny)
64226422
Printer << "@isolated(any) ";
64236423
break;
6424+
6425+
case FunctionTypeIsolation::Kind::NonIsolatedCaller:
6426+
Printer << "@execution(caller) ";
6427+
break;
64246428
}
64256429

64266430
if (!Options.excludeAttrKind(TypeAttrKind::Sendable) && info.isSendable()) {

lib/SILGen/SILGenConcurrency.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,7 @@ SILGenFunction::emitFunctionTypeIsolation(SILLocation loc,
563563

564564
// Emit nonisolated by simply emitting Optional.none in the result type.
565565
case FunctionTypeIsolation::Kind::NonIsolated:
566+
case FunctionTypeIsolation::Kind::NonIsolatedCaller:
566567
return emitNonIsolatedIsolation(loc);
567568

568569
// Emit global actor isolation by loading .shared from the global actor,

lib/SILGen/SILGenPoly.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5439,6 +5439,10 @@ static void buildThunkBody(SILGenFunction &SGF, SILLocation loc,
54395439
case FunctionTypeIsolation::Kind::NonIsolated:
54405440
break;
54415441

5442+
case FunctionTypeIsolation::Kind::NonIsolatedCaller:
5443+
hopToIsolatedParameter = true;
5444+
break;
5445+
54425446
// For a function with parameter isolation, we'll have to dig the
54435447
// argument out after translation but before making the call.
54445448
case FunctionTypeIsolation::Kind::Parameter:

lib/Sema/CSSimplify.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2964,6 +2964,10 @@ ConstraintSystem::matchFunctionIsolations(FunctionType *func1,
29642964
case FunctionTypeIsolation::Kind::NonIsolated:
29652965
return true;
29662966

2967+
// A thunk is going to pass `nil` to the isolated parameter.
2968+
case FunctionTypeIsolation::Kind::NonIsolatedCaller:
2969+
return matchIfConversion();
2970+
29672971
// Erasing global-actor isolation to non-isolation can admit data
29682972
// races; such violations are diagnosed by the actor isolation checker.
29692973
// We deliberately do not allow actor isolation violations to influence
@@ -2984,6 +2988,35 @@ ConstraintSystem::matchFunctionIsolations(FunctionType *func1,
29842988
}
29852989
llvm_unreachable("bad kind");
29862990

2991+
// Converting to a caller isolated async function type.
2992+
case FunctionTypeIsolation::Kind::NonIsolatedCaller:
2993+
switch (isolation1.getKind()) {
2994+
// Exact match.
2995+
case FunctionTypeIsolation::Kind::NonIsolatedCaller:
2996+
return true;
2997+
2998+
// Global actor: Thunk will hop to the global actor
2999+
// and would ignore passed in isolation.
3000+
// Erased: Just like global actor but would hop to
3001+
// the isolation stored in the @isolated(any) function.
3002+
case FunctionTypeIsolation::Kind::GlobalActor:
3003+
case FunctionTypeIsolation::Kind::Erased:
3004+
return matchIfConversion();
3005+
3006+
// In this case the isolation is dependent on a
3007+
// specific actor passed in as the isolation parameter
3008+
// and the thunk won't have it.
3009+
case FunctionTypeIsolation::Kind::Parameter:
3010+
return false;
3011+
3012+
// For asynchronous: Thunk would hop the appropriate actor.
3013+
// For synchronous: Thunk would call the function without
3014+
// a hop.
3015+
case FunctionTypeIsolation::Kind::NonIsolated:
3016+
return matchIfConversion();
3017+
}
3018+
llvm_unreachable("bad kind");
3019+
29873020
// Converting to a global-actor-isolated type.
29883021
case FunctionTypeIsolation::Kind::GlobalActor:
29893022
switch (isolation1.getKind()) {
@@ -3004,6 +3037,11 @@ ConstraintSystem::matchFunctionIsolations(FunctionType *func1,
30043037
case FunctionTypeIsolation::Kind::NonIsolated:
30053038
return matchIfConversion();
30063039

3040+
// A thunk is going to pass in an instance of a global actor
3041+
// to the isolated parameter.
3042+
case FunctionTypeIsolation::Kind::NonIsolatedCaller:
3043+
return matchIfConversion();
3044+
30073045
// Parameter isolation cannot be altered in the same way.
30083046
case FunctionTypeIsolation::Kind::Parameter:
30093047
return false;
@@ -3030,6 +3068,10 @@ ConstraintSystem::matchFunctionIsolations(FunctionType *func1,
30303068
case FunctionTypeIsolation::Kind::GlobalActor:
30313069
return matchIfConversion();
30323070

3071+
// A thunk is going to forward the isolation.
3072+
case FunctionTypeIsolation::Kind::NonIsolatedCaller:
3073+
return matchIfConversion();
3074+
30333075
// Don't allow dynamically-isolated function types to convert to
30343076
// any specific isolation for the same policy reasons that we don't
30353077
// want to allow global-actors to change.
@@ -3050,6 +3092,11 @@ ConstraintSystem::matchFunctionIsolations(FunctionType *func1,
30503092
case FunctionTypeIsolation::Kind::GlobalActor:
30513093
return matchIfConversion(/*erasure*/ true);
30523094

3095+
// It's not possible to form a thunk for this case because
3096+
// we don't know what to pass to the isolated parameter.
3097+
case FunctionTypeIsolation::Kind::NonIsolatedCaller:
3098+
return false;
3099+
30533100
// Parameter isolation is value-dependent and can't be erased in the
30543101
// abstract, though. We need to be able to recover the isolation from
30553102
// a value.

lib/Sema/TypeCheckType.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4206,7 +4206,7 @@ NeverNullType TypeResolver::resolveASTFunctionType(
42064206
switch (isolation.getKind()) {
42074207
case FunctionTypeIsolation::Kind::NonIsolated:
42084208
break;
4209-
4209+
42104210
case FunctionTypeIsolation::Kind::GlobalActor:
42114211
diagnoseInvalid(
42124212
repr, executionAttr->getAtLoc(),
@@ -4228,15 +4228,19 @@ NeverNullType TypeResolver::resolveASTFunctionType(
42284228
diag::
42294229
attr_execution_concurrent_type_attr_incompatible_with_isolated_any);
42304230
break;
4231+
4232+
case FunctionTypeIsolation::Kind::NonIsolatedCaller:
4233+
llvm_unreachable("cannot happen because multiple @execution attributes "
4234+
"aren't allowed.");
42314235
}
42324236

42334237
if (!repr->isInvalid()) {
42344238
switch (executionAttr->getBehavior()) {
42354239
case ExecutionKind::Concurrent:
4236-
// TODO: We need to introduce a new isolation kind to support this.
4240+
isolation = FunctionTypeIsolation::forNonIsolated();
42374241
break;
42384242
case ExecutionKind::Caller:
4239-
isolation = FunctionTypeIsolation::forNonIsolated();
4243+
isolation = FunctionTypeIsolation::forNonIsolatedCaller();
42404244
break;
42414245
}
42424246
}

lib/Serialization/Deserialization.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7133,6 +7133,8 @@ detail::function_deserializer::deserialize(ModuleFile &MF,
71337133
auto isolation = swift::FunctionTypeIsolation::forNonIsolated();
71347134
if (rawIsolation == unsigned(FunctionTypeIsolation::NonIsolated)) {
71357135
// do nothing
7136+
} else if (rawIsolation == unsigned(FunctionTypeIsolation::NonIsolatedCaller)) {
7137+
isolation = swift::FunctionTypeIsolation::forNonIsolatedCaller();
71367138
} else if (rawIsolation == unsigned(FunctionTypeIsolation::Parameter)) {
71377139
isolation = swift::FunctionTypeIsolation::forParameter();
71387140
} else if (rawIsolation == unsigned(FunctionTypeIsolation::Erased)) {

lib/Serialization/ModuleFormat.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
5858
/// describe what change you made. The content of this comment isn't important;
5959
/// it just ensures a conflict if two people change the module format.
6060
/// Don't worry about adhering to the 80-column limit for this line.
61-
const uint16_t SWIFTMODULE_VERSION_MINOR = 921; // remove alloc_vector
61+
const uint16_t SWIFTMODULE_VERSION_MINOR = 922; // function type isolation - caller
6262

6363
/// A standard hash seed used for all string hashes in a serialized module.
6464
///
@@ -707,6 +707,7 @@ enum class FunctionTypeIsolation : uint8_t {
707707
Parameter,
708708
Erased,
709709
GlobalActorOffset, // Add this to the global actor type ID
710+
NonIsolatedCaller,
710711
};
711712
using FunctionTypeIsolationField = TypeIDField;
712713

lib/Serialization/Serialization.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5781,6 +5781,8 @@ class Serializer::TypeSerializer : public TypeVisitor<TypeSerializer> {
57815781
switch (isolation.getKind()) {
57825782
case swift::FunctionTypeIsolation::Kind::NonIsolated:
57835783
return unsigned(FunctionTypeIsolation::NonIsolated);
5784+
case swift::FunctionTypeIsolation::Kind::NonIsolatedCaller:
5785+
return unsigned(FunctionTypeIsolation::NonIsolatedCaller);
57845786
case swift::FunctionTypeIsolation::Kind::Parameter:
57855787
return unsigned(FunctionTypeIsolation::Parameter);
57865788
case swift::FunctionTypeIsolation::Kind::Erased:

0 commit comments

Comments
 (0)