Skip to content

Commit 43e1c54

Browse files
committed
[sending] Make the operation of Builtin.createAsyncTask/friends a sending non-Sendable function instead of an @sendable function.
This matches the interface of the public stdlib APIs that wrap these builtin calls.
1 parent d54e6ba commit 43e1c54

File tree

7 files changed

+101
-43
lines changed

7 files changed

+101
-43
lines changed

include/swift/AST/ASTSynthesis.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,27 @@ ParamDecl *synthesizeParamDecl(SynthesisContext &SC,
372372
param->setSpecifier(s.specifier);
373373
return param;
374374
}
375+
376+
template <class S>
377+
struct SendingParamSynthesizer {
378+
S sub;
379+
};
380+
381+
template <class S>
382+
constexpr SendingParamSynthesizer<S> _sending(S sub) {
383+
return {sub};
384+
}
385+
386+
template <class S>
387+
ParamDecl *synthesizeParamDecl(SynthesisContext &SC,
388+
const SendingParamSynthesizer<S> &s,
389+
const char *label = nullptr) {
390+
auto param = synthesizeParamDecl(SC, s.sub, label);
391+
if (SC.Context.LangOpts.hasFeature(Feature::SendingArgsAndResults))
392+
param->setSending();
393+
return param;
394+
}
395+
375396
template <class S>
376397
FunctionType::Param synthesizeParamType(SynthesisContext &SC,
377398
const SpecifiedParamSynthesizer<S> &s) {

include/swift/AST/Builtins.def

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -959,7 +959,7 @@ BUILTIN_MISC_OPERATION(UnprotectedAddressOfBorrowOpaque, "unprotectedAddressOfBo
959959
/// initialSerialExecutor: (Builtin.Executor)? = nil,
960960
/// taskGroup: Builtin.RawPointer? = nil,
961961
/// initialTaskExecutor: (Builtin.Executor)? = nil,
962-
/// operation: @escaping () async throws -> T)
962+
/// operation: sending @escaping () async throws -> T)
963963
/// -> Builtin.NativeObject, Builtin.RawPointer)
964964
///
965965
/// Create a new task.
@@ -969,15 +969,15 @@ BUILTIN_SIL_OPERATION(CreateTask, "createTask", Special)
969969
/// initialSerialExecutor: (Builtin.Executor)? = nil,
970970
/// taskGroup: Builtin.RawPointer? = nil,
971971
/// initialTaskExecutor: (Builtin.Executor)? = nil,
972-
/// operation: @escaping () async throws -> ())
972+
/// operation: sending @escaping () async throws -> ())
973973
/// -> (Builtin.NativeObject, Builtin.RawPointer)
974974
///
975975
/// Create a new discarding task.
976976
BUILTIN_SIL_OPERATION(CreateDiscardingTask, "createDiscardingTask", Special)
977977

978978
/// createAsyncTask(): (
979979
/// Int, // task-creation flags
980-
/// @escaping () async throws -> T // function
980+
/// sending @escaping () async throws -> T // function
981981
/// ) -> Builtin.NativeObject
982982
///
983983
/// Legacy spelling of:
@@ -988,7 +988,7 @@ BUILTIN_MISC_OPERATION_WITH_SILGEN(CreateAsyncTask,
988988
/// createAsyncTaskInGroup(): (
989989
/// Int, // flags
990990
/// Builtin.RawPointer, // group
991-
/// @escaping () async throws -> T // function
991+
/// sending @escaping () async throws -> T // function
992992
/// ) -> Builtin.NativeObject
993993
///
994994
/// Legacy spelling of:
@@ -999,7 +999,7 @@ BUILTIN_SIL_OPERATION(CreateAsyncTaskInGroup,
999999
/// createAsyncDiscardingTaskInGroup(): (
10001000
/// Int, // flags
10011001
/// Builtin.RawPointer, // group
1002-
/// @escaping () async throws -> Void // function
1002+
/// sending @escaping () async throws -> Void // function
10031003
/// ) -> Builtin.NativeObject
10041004
///
10051005
/// Legacy spelling of:
@@ -1010,7 +1010,7 @@ BUILTIN_SIL_OPERATION(CreateAsyncDiscardingTaskInGroup,
10101010
/// createAsyncTaskWithExecutor(): (
10111011
/// Int, // flags
10121012
/// Builtin.Executor, // executor
1013-
/// @escaping () async throws -> T // function
1013+
/// sending @escaping () async throws -> T // function
10141014
/// ) -> Builtin.NativeObject
10151015
///
10161016
/// Legacy spelling of:
@@ -1022,7 +1022,7 @@ BUILTIN_SIL_OPERATION(CreateAsyncTaskWithExecutor,
10221022
/// Int, // flags
10231023
/// Builtin.RawPointer, // group
10241024
/// Builtin.Executor, // executor
1025-
/// @escaping () async throws -> T // function
1025+
/// sending @escaping () async throws -> T // function
10261026
/// ) -> Builtin.NativeObject
10271027
///
10281028
/// Legacy spelling of:
@@ -1034,7 +1034,7 @@ BUILTIN_SIL_OPERATION(CreateAsyncTaskInGroupWithExecutor,
10341034
/// Int, // flags
10351035
/// Builtin.RawPointer, // group
10361036
/// Builtin.Executor, // executor
1037-
/// @escaping () async throws -> Void // function
1037+
/// sending @escaping () async throws -> Void // function
10381038
/// ) -> Builtin.NativeObject
10391039
///
10401040
/// Legacy spelling of:

lib/AST/Builtins.cpp

Lines changed: 42 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -708,10 +708,15 @@ namespace {
708708

709709
template <class G>
710710
void addParameter(const G &generator,
711-
ParamSpecifier ownership = ParamSpecifier::Default) {
711+
ParamSpecifier ownership = ParamSpecifier::Default,
712+
bool isSending = false) {
712713
Type gTyIface = generator.build(*this);
713714
auto flags = ParameterTypeFlags().withOwnershipSpecifier(ownership);
714-
InterfaceParams.emplace_back(gTyIface, Identifier(), flags);
715+
auto p = AnyFunctionType::Param(gTyIface, Identifier(), flags);
716+
if (isSending) {
717+
p = p.withFlags(p.getParameterFlags().withSending(true));
718+
}
719+
InterfaceParams.push_back(p);
715720
}
716721

717722
template <class G>
@@ -1533,18 +1538,20 @@ static ValueDecl *getCreateTask(ASTContext &ctx, Identifier id) {
15331538
return getBuiltinFunction(
15341539
ctx, id, _thin, _generics(_unrestricted, _conformsToDefaults(0)),
15351540
_parameters(
1536-
_label("flags", _swiftInt),
1537-
_label("initialSerialExecutor", _defaulted(_optional(_executor), _nil)),
1538-
_label("taskGroup", _defaulted(_optional(_rawPointer), _nil)),
1539-
_label("initialTaskExecutor", _defaulted(_optional(_executor), _nil)),
1540-
_label("initialTaskExecutorConsuming",
1541+
_label("flags", _swiftInt),
1542+
_label("initialSerialExecutor",
1543+
_defaulted(_optional(_executor), _nil)),
1544+
_label("taskGroup", _defaulted(_optional(_rawPointer), _nil)),
1545+
_label("initialTaskExecutor", _defaulted(_optional(_executor), _nil)),
1546+
_label("initialTaskExecutorConsuming",
15411547
_defaulted(_consuming(_optional(_bincompatType(
15421548
/*if*/ taskExecutorIsAvailable,
15431549
_existential(_taskExecutor),
15441550
/*else*/ _executor))),
15451551
_nil)),
1546-
_label("operation", _function(_async(_throws(_sendable(_thick))),
1547-
_typeparam(0), _parameters()))),
1552+
_label("operation",
1553+
_sending(_function(_async(_throws(_thick)), _typeparam(0),
1554+
_parameters())))),
15481555
_tuple(_nativeObject, _rawPointer));
15491556
}
15501557

@@ -1555,18 +1562,19 @@ static ValueDecl *getCreateDiscardingTask(ASTContext &ctx, Identifier id) {
15551562
return getBuiltinFunction(
15561563
ctx, id, _thin,
15571564
_parameters(
1558-
_label("flags", _swiftInt),
1559-
_label("initialSerialExecutor", _defaulted(_optional(_executor), _nil)),
1560-
_label("taskGroup", _defaulted(_optional(_rawPointer), _nil)),
1561-
_label("initialTaskExecutor", _defaulted(_optional(_executor), _nil)),
1562-
_label("initialTaskExecutorConsuming",
1563-
_defaulted(_consuming(_optional(_bincompatType(
1564-
/*if*/ taskExecutorIsAvailable,
1565-
_existential(_taskExecutor),
1566-
/*else*/ _executor))),
1567-
_nil)),
1568-
_label("operation", _function(_async(_throws(_sendable(_thick))),
1569-
_void, _parameters()))),
1565+
_label("flags", _swiftInt),
1566+
_label("initialSerialExecutor",
1567+
_defaulted(_optional(_executor), _nil)),
1568+
_label("taskGroup", _defaulted(_optional(_rawPointer), _nil)),
1569+
_label("initialTaskExecutor", _defaulted(_optional(_executor), _nil)),
1570+
_label("initialTaskExecutorConsuming",
1571+
_defaulted(_consuming(_optional(_bincompatType(
1572+
/*if*/ taskExecutorIsAvailable,
1573+
_existential(_taskExecutor),
1574+
/*else*/ _executor))),
1575+
_nil)),
1576+
_label("operation", _sending(_function(_async(_throws(_thick)), _void,
1577+
_parameters())))),
15701578
_tuple(_nativeObject, _rawPointer));
15711579
}
15721580

@@ -1584,16 +1592,25 @@ static ValueDecl *getCreateAsyncTask(ASTContext &ctx, Identifier id,
15841592
if (withTaskExecutor) {
15851593
builder.addParameter(makeConcrete(ctx.TheExecutorType)); // executor
15861594
}
1587-
auto extInfo = ASTExtInfoBuilder().withAsync().withThrows()
1588-
.withSendable(true).build();
1595+
1596+
bool areSendingArgsEnabled =
1597+
ctx.LangOpts.hasFeature(Feature::SendingArgsAndResults);
1598+
1599+
auto extInfo = ASTExtInfoBuilder()
1600+
.withAsync()
1601+
.withThrows()
1602+
.withSendable(!areSendingArgsEnabled)
1603+
.build();
15891604
Type operationResultType;
15901605
if (isDiscarding) {
15911606
operationResultType = TupleType::getEmpty(ctx); // ()
15921607
} else {
15931608
operationResultType = makeGenericParam().build(builder); // <T>
15941609
}
1595-
builder.addParameter(makeConcrete(
1596-
FunctionType::get({}, operationResultType, extInfo))); // operation
1610+
builder.addParameter(
1611+
makeConcrete(FunctionType::get({}, operationResultType, extInfo)),
1612+
ParamSpecifier::Default,
1613+
areSendingArgsEnabled /*isSending*/); // operation
15971614
builder.setResult(makeConcrete(getAsyncTaskAndContextType(ctx)));
15981615
return builder.build(id);
15991616
}

lib/SIL/Verifier/SILVerifier.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2408,8 +2408,12 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
24082408
}
24092409
auto fnType = requireObjectType(SILFunctionType, arguments[5],
24102410
"result of createAsyncTask");
2411-
auto expectedExtInfo =
2412-
SILExtInfoBuilder().withAsync(true).withSendable(true).build();
2411+
bool haveSending =
2412+
F.getASTContext().LangOpts.hasFeature(Feature::SendingArgsAndResults);
2413+
auto expectedExtInfo = SILExtInfoBuilder()
2414+
.withAsync(true)
2415+
.withSendable(!haveSending)
2416+
.build();
24132417
require(fnType->getExtInfo().isEqualTo(expectedExtInfo, /*clang types*/true),
24142418
"function argument to createAsyncTask has incorrect ext info");
24152419
// FIXME: it'd be better if we took a consuming closure here

lib/SILGen/SILGenBuiltin.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1631,11 +1631,13 @@ static ManagedValue emitCreateAsyncTask(SILGenFunction &SGF, SILLocation loc,
16311631

16321632
auto &&fnArg = nextArg();
16331633

1634+
bool hasSending = ctx.LangOpts.hasFeature(Feature::SendingArgsAndResults);
1635+
16341636
auto extInfo =
16351637
ASTExtInfoBuilder()
16361638
.withAsync()
16371639
.withThrows()
1638-
.withSendable(true)
1640+
.withSendable(!hasSending)
16391641
.withRepresentation(GenericFunctionType::Representation::Swift)
16401642
.build();
16411643

@@ -1757,10 +1759,12 @@ SILGenFunction::emitCreateAsyncMainTask(SILLocation loc, SubstitutionMap subs,
17571759
ManagedValue mainFunctionRef) {
17581760
auto &ctx = getASTContext();
17591761
CanType flagsType = ctx.getIntType()->getCanonicalType();
1762+
bool hasSending = ctx.LangOpts.hasFeature(Feature::SendingArgsAndResults);
17601763
CanType functionType =
1761-
FunctionType::get({}, ctx.TheEmptyTupleType,
1762-
ASTExtInfo().withAsync().withThrows().withSendable(true))
1763-
->getCanonicalType();
1764+
FunctionType::get(
1765+
{}, ctx.TheEmptyTupleType,
1766+
ASTExtInfo().withAsync().withThrows().withSendable(!hasSending))
1767+
->getCanonicalType();
17641768

17651769
using Param = FunctionType::Param;
17661770
PreparedArguments args({Param(flagsType), Param(functionType)});

lib/SILOptimizer/Analysis/RegionAnalysis.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1859,11 +1859,23 @@ class PartitionOpTranslator {
18591859
translateSILMultiAssign(applyResults, pai->getOperandValues());
18601860
}
18611861

1862+
void translateCreateAsyncTask(BuiltinInst *bi) {
1863+
if (auto value = tryToTrackValue(bi->getOperand(1))) {
1864+
builder.addRequire(value->getRepresentative().getValue());
1865+
builder.addTransfer(value->getRepresentative().getValue(),
1866+
&bi->getAllOperands()[1]);
1867+
}
1868+
}
1869+
18621870
void translateSILBuiltin(BuiltinInst *bi) {
18631871
if (auto kind = bi->getBuiltinKind()) {
18641872
if (kind == BuiltinValueKind::StartAsyncLetWithLocalBuffer) {
18651873
return translateAsyncLetStart(bi);
18661874
}
1875+
1876+
if (kind == BuiltinValueKind::CreateAsyncTask) {
1877+
return translateCreateAsyncTask(bi);
1878+
}
18671879
}
18681880

18691881
// If we do not have a special builtin, just do a multi-assign. Builtins do

test/Concurrency/async_main.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,10 @@ func asyncFunc() async {
7272
// CHECK-SIL-NEXT: [[TASK_EXECUTOR_UNOWNED:%.*]] = enum $Optional<Builtin.Executor>, #Optional.none
7373
// CHECK-SIL-NEXT: [[TASK_EXECUTOR_OWNED:%.*]] = enum $Optional<any TaskExecutor>, #Optional.none
7474
// CHECK-SIL-NEXT: // function_ref thunk for @escaping @convention(thin) @async () -> ()
75-
// CHECK-SIL-NEXT: [[THUNK_FN:%.*]] = function_ref @$sIetH_yts5Error_pIeghHrzo_TR : $@convention(thin) @Sendable @async (@convention(thin) @async () -> ()) -> (@out (), @error any Error)
76-
// CHECK-SIL-NEXT: [[THUNK:%.*]] = partial_apply [callee_guaranteed] [[THUNK_FN]]([[ASYNC_MAIN_FN]]) : $@convention(thin) @Sendable @async (@convention(thin) @async () -> ()) -> (@out (), @error any Error)
77-
// CHECK-SIL-NEXT: [[CONVERTED_THUNK:%.*]] = convert_function [[THUNK]] : $@Sendable @async @callee_guaranteed () -> (@out (), @error any Error) to $@Sendable @async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for <()>
78-
// CHECK-SIL-NEXT: [[TASK_RESULT:%.*]] = builtin "createAsyncTask"<()>([[FLAGS]] : $Int, [[OPT_SERIAL_EXECUTOR]] : $Optional<Builtin.Executor>, [[GROUP]] : $Optional<Builtin.RawPointer>, [[TASK_EXECUTOR_UNOWNED]] : $Optional<Builtin.Executor>, [[TASK_EXECUTOR_OWNED]] : $Optional<any TaskExecutor>, [[CONVERTED_THUNK]] : $@Sendable @async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for <()>) : $(Builtin.NativeObject, Builtin.RawPointer)
75+
// CHECK-SIL-NEXT: [[THUNK_FN:%.*]] = function_ref @$sIetH_yts5Error_pIegHrzo_TR : $@convention(thin) @async (@convention(thin) @async () -> ()) -> (@out (), @error any Error)
76+
// CHECK-SIL-NEXT: [[THUNK:%.*]] = partial_apply [callee_guaranteed] [[THUNK_FN]]([[ASYNC_MAIN_FN]]) : $@convention(thin) @async (@convention(thin) @async () -> ()) -> (@out (), @error any Error)
77+
// CHECK-SIL-NEXT: [[CONVERTED_THUNK:%.*]] = convert_function [[THUNK]] : $@async @callee_guaranteed () -> (@out (), @error any Error) to $@async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for <()>
78+
// CHECK-SIL-NEXT: [[TASK_RESULT:%.*]] = builtin "createAsyncTask"<()>([[FLAGS]] : $Int, [[OPT_SERIAL_EXECUTOR]] : $Optional<Builtin.Executor>, [[GROUP]] : $Optional<Builtin.RawPointer>, [[TASK_EXECUTOR_UNOWNED]] : $Optional<Builtin.Executor>, [[TASK_EXECUTOR_OWNED]] : $Optional<any TaskExecutor>, [[CONVERTED_THUNK]] : $@async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for <()>) : $(Builtin.NativeObject, Builtin.RawPointer)
7979
// CHECK-SIL-NEXT: [[TASK:%.*]] = tuple_extract [[TASK_RESULT]] : $(Builtin.NativeObject, Builtin.RawPointer), 0
8080
// CHECK-SIL-NEXT: // function_ref swift_job_run
8181
// CHECK-SIL-NEXT: [[RUN_FN:%.*]] = function_ref @swift_job_run : $@convention(thin) (UnownedJob, UnownedSerialExecutor) -> ()

0 commit comments

Comments
 (0)