From a94727d401943c69fba8e6ed26332a0126f6466c Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Fri, 21 Mar 2025 11:26:26 -0700 Subject: [PATCH 1/2] [ast] Teach ASTDumper how to dump FunctionTypeIsolation on a FunctionType. Otherwise, it gets confusing when debugging in the debugger since dumpPrint will print out the function type isolation, but dump will not. --- lib/AST/ASTDumper.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 4f4cd4be38ab8..28d3f0819e7d6 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -6299,6 +6299,22 @@ namespace { break; } } + auto isolation = T->getIsolation(); + switch (isolation.getKind()) { + case FunctionTypeIsolation::Kind::NonIsolated: + case FunctionTypeIsolation::Kind::Parameter: + break; + case FunctionTypeIsolation::Kind::GlobalActor: + printRec(isolation.getGlobalActorType(), + Label::always("global_actor")); + break; + case FunctionTypeIsolation::Kind::Erased: + printFlag("@isolated(any)"); + break; + case FunctionTypeIsolation::Kind::NonIsolatedCaller: + printFlag("@execution(caller)"); + break; + } } if (Type globalActor = T->getGlobalActor()) { printFieldQuoted(globalActor.getString(), Label::always("global_actor")); From 2d5dd7502fe9251db6edbffeab31ac03db2cd233 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Fri, 21 Mar 2025 11:27:25 -0700 Subject: [PATCH 2/2] [concurrency] Make sure that TypeLowering inserts the extra actor parameter for @execution(caller) parameters. Previously, we handled cases where we had an actual SILDeclRef constant (e.x.: an actual function ref), but we did not handle cases where we did not have a constant but instead just had a FunctionTypeIsolation. We now handle that correctly. --- include/swift/AST/ActorIsolation.h | 4 +++ lib/SIL/IR/SILFunctionType.cpp | 10 +++++-- test/SILGen/execution_attr.swift | 48 ++++++++++++++++++++++++++++-- 3 files changed, 58 insertions(+), 4 deletions(-) diff --git a/include/swift/AST/ActorIsolation.h b/include/swift/AST/ActorIsolation.h index 6dba92fdad5f2..9d2f60388e90a 100644 --- a/include/swift/AST/ActorIsolation.h +++ b/include/swift/AST/ActorIsolation.h @@ -233,6 +233,10 @@ class ActorIsolation { bool isDistributedActor() const; + bool isCallerIsolationInheriting() const { + return getKind() == CallerIsolationInheriting; + } + Type getGlobalActor() const { assert(isGlobalActor()); diff --git a/lib/SIL/IR/SILFunctionType.cpp b/lib/SIL/IR/SILFunctionType.cpp index ac7d7f6cb2c18..5f5156b15ab43 100644 --- a/lib/SIL/IR/SILFunctionType.cpp +++ b/lib/SIL/IR/SILFunctionType.cpp @@ -1662,8 +1662,7 @@ class DestructureInputs { // If we are an async function that is unspecified or nonisolated, insert an // isolated parameter if AsyncCallerExecution is enabled. - if (IsolationInfo && - IsolationInfo->getKind() == ActorIsolation::CallerIsolationInheriting && + if (IsolationInfo && IsolationInfo->isCallerIsolationInheriting() && extInfoBuilder.isAsync()) { auto actorProtocol = TC.Context.getProtocol(KnownProtocolKind::Actor); auto actorType = @@ -2584,6 +2583,13 @@ static CanSILFunctionType getSILFunctionType( actorIsolation = getActorIsolationOfContext(constant->getInnermostDeclContext()); } + } else if (substFnInterfaceType->hasExtInfo() && + substFnInterfaceType->getExtInfo() + .getIsolation() + .isNonIsolatedCaller()) { + // If our function type is a nonisolated caller and we can not infer from + // our constant, we must be caller isolation inheriting. + actorIsolation = ActorIsolation::forCallerIsolationInheriting(); } DestructureInputs destructurer(expansionContext, TC, conventions, foreignInfo, actorIsolation, inputs, diff --git a/test/SILGen/execution_attr.swift b/test/SILGen/execution_attr.swift index c6449cdf78919..b3b8ba348a367 100644 --- a/test/SILGen/execution_attr.swift +++ b/test/SILGen/execution_attr.swift @@ -1,5 +1,5 @@ -// RUN: %target-swift-emit-silgen %s -enable-experimental-feature ExecutionAttribute | %FileCheck %s -// RUN: %target-swift-emit-silgen %s -enable-experimental-feature ExecutionAttribute -enable-experimental-feature AsyncCallerExecution | %FileCheck %s +// RUN: %target-swift-emit-silgen %s -enable-experimental-feature ExecutionAttribute | %FileCheck -check-prefix CHECK -check-prefix DISABLED %s +// RUN: %target-swift-emit-silgen %s -enable-experimental-feature ExecutionAttribute -enable-experimental-feature AsyncCallerExecution | %FileCheck -check-prefix CHECK -check-prefix ENABLED %s // REQUIRES: concurrency // REQUIRES: asserts @@ -20,3 +20,47 @@ func executionCaller() async {} // CHECK: sil hidden [ossa] @$s14execution_attr0A10ConcurrentyyYaF : $@convention(thin) @async () -> () { @execution(concurrent) func executionConcurrent() async {} + +// DISABLED: sil hidden [ossa] @$s14execution_attr0A15CallerParameteryyyyYaYCXEYaF : $@convention(thin) @async (@guaranteed @noescape @async @callee_guaranteed (@sil_isolated @sil_implicit_leading_param @guaranteed Optional) -> ()) -> () { +// ENABLED: sil hidden [ossa] @$s14execution_attr0A15CallerParameteryyyyYaYCXEYaF : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional, @guaranteed @noescape @async @callee_guaranteed (@sil_isolated @sil_implicit_leading_param @guaranteed Optional) -> ()) -> () { +// CHECK: } // end sil function '$s14execution_attr0A15CallerParameteryyyyYaYCXEYaF' +func executionCallerParameter(_ x: @execution(caller) () async -> ()) async { + await x() +} + +// DISABLED-LABEL: sil hidden [ossa] @$s14execution_attr0A19ConcurrentParameteryyyyYaXEYaF : $@convention(thin) @async (@guaranteed @noescape @async @callee_guaranteed () -> ()) -> () { +// ENABLED-LABEL: sil hidden [ossa] @$s14execution_attr0A19ConcurrentParameteryyyyYaXEYaF : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional, @guaranteed @noescape @async @callee_guaranteed () -> ()) -> () { +func executionConcurrentParameter(_ x: @execution(concurrent) () async -> ()) async { + await x() +} + +struct S { + let field: @execution(caller) () async -> () +} + +// DISABLED: sil hidden [ossa] @$s14execution_attr0A11CallerFieldyyAA1SVYaF : $@convention(thin) @async (@guaranteed S) -> () { +// DISABLED: bb0([[ARG:%.*]] : @guaranteed $S): +// DISABLED: [[FIELD:%.*]] = struct_extract [[ARG]] +// DISABLED: [[FIELD_COPY:%.*]] = copy_value [[FIELD]] +// DISABLED: [[ACTOR_NONE:%.*]] = enum $Optional, #Optional.none!enumelt +// DISABLED: [[BORROWED_FIELD:%.*]] = begin_borrow [[FIELD_COPY]] +// DISABLED: apply [[BORROWED_FIELD]]([[ACTOR_NONE]]) +// DISABLED: } // end sil function '$s14execution_attr0A11CallerFieldyyAA1SVYaF' + +// ENABLED: sil hidden [ossa] @$s14execution_attr0A11CallerFieldyyAA1SVYaF : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional, @guaranteed S) -> () { +// ENABLED: bb0([[ACTOR:%.*]] : @guaranteed $Optional, [[ARG:%.*]] : @guaranteed $S): +// ENABLED: [[FIELD:%.*]] = struct_extract [[ARG]] +// ENABLED: [[FIELD_COPY:%.*]] = copy_value [[FIELD]] +// ENABLED: [[BORROWED_FIELD:%.*]] = begin_borrow [[FIELD_COPY]] +// ENABLED: apply [[BORROWED_FIELD]]([[ACTOR]]) +// ENABLED: } // end sil function '$s14execution_attr0A11CallerFieldyyAA1SVYaF' +func executionCallerField(_ s: S) async { + await s.field() +} + +extension S { + // CHECK-LABEL: // S.executionCallerFieldMethod(_:) + // CHECK: // Isolation: unspecified + // CHECK: sil hidden [ossa] @$s14execution_attr1SV0A17CallerFieldMethodyyyyYaYCXEF : $@convention(method) (@guaranteed @noescape @async @callee_guaranteed (@sil_isolated @sil_implicit_leading_param @guaranteed Optional) -> (), @guaranteed S) -> () { + func executionCallerFieldMethod(_ x: @execution(caller) () async -> ()) {} +}