Skip to content

Commit fc4507b

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. (cherry picked from commit 8fb74fe)
1 parent 3a340bf commit fc4507b

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
@@ -975,7 +975,7 @@ BUILTIN_MISC_OPERATION(UnprotectedAddressOfBorrowOpaque, "unprotectedAddressOfBo
975975
/// initialSerialExecutor: (Builtin.Executor)? = nil,
976976
/// taskGroup: Builtin.RawPointer? = nil,
977977
/// initialTaskExecutor: (Builtin.Executor)? = nil,
978-
/// operation: @escaping () async throws -> T)
978+
/// operation: sending @escaping () async throws -> T)
979979
/// -> Builtin.NativeObject, Builtin.RawPointer)
980980
///
981981
/// Create a new task.
@@ -985,15 +985,15 @@ BUILTIN_SIL_OPERATION(CreateTask, "createTask", Special)
985985
/// initialSerialExecutor: (Builtin.Executor)? = nil,
986986
/// taskGroup: Builtin.RawPointer? = nil,
987987
/// initialTaskExecutor: (Builtin.Executor)? = nil,
988-
/// operation: @escaping () async throws -> ())
988+
/// operation: sending @escaping () async throws -> ())
989989
/// -> (Builtin.NativeObject, Builtin.RawPointer)
990990
///
991991
/// Create a new discarding task.
992992
BUILTIN_SIL_OPERATION(CreateDiscardingTask, "createDiscardingTask", Special)
993993

994994
/// createAsyncTask(): (
995995
/// Int, // task-creation flags
996-
/// @escaping () async throws -> T // function
996+
/// sending @escaping () async throws -> T // function
997997
/// ) -> Builtin.NativeObject
998998
///
999999
/// Legacy spelling of:
@@ -1004,7 +1004,7 @@ BUILTIN_MISC_OPERATION_WITH_SILGEN(CreateAsyncTask,
10041004
/// createAsyncTaskInGroup(): (
10051005
/// Int, // flags
10061006
/// Builtin.RawPointer, // group
1007-
/// @escaping () async throws -> T // function
1007+
/// sending @escaping () async throws -> T // function
10081008
/// ) -> Builtin.NativeObject
10091009
///
10101010
/// Legacy spelling of:
@@ -1015,7 +1015,7 @@ BUILTIN_SIL_OPERATION(CreateAsyncTaskInGroup,
10151015
/// createAsyncDiscardingTaskInGroup(): (
10161016
/// Int, // flags
10171017
/// Builtin.RawPointer, // group
1018-
/// @escaping () async throws -> Void // function
1018+
/// sending @escaping () async throws -> Void // function
10191019
/// ) -> Builtin.NativeObject
10201020
///
10211021
/// Legacy spelling of:
@@ -1026,7 +1026,7 @@ BUILTIN_SIL_OPERATION(CreateAsyncDiscardingTaskInGroup,
10261026
/// createAsyncTaskWithExecutor(): (
10271027
/// Int, // flags
10281028
/// Builtin.Executor, // executor
1029-
/// @escaping () async throws -> T // function
1029+
/// sending @escaping () async throws -> T // function
10301030
/// ) -> Builtin.NativeObject
10311031
///
10321032
/// Legacy spelling of:
@@ -1038,7 +1038,7 @@ BUILTIN_SIL_OPERATION(CreateAsyncTaskWithExecutor,
10381038
/// Int, // flags
10391039
/// Builtin.RawPointer, // group
10401040
/// Builtin.Executor, // executor
1041-
/// @escaping () async throws -> T // function
1041+
/// sending @escaping () async throws -> T // function
10421042
/// ) -> Builtin.NativeObject
10431043
///
10441044
/// Legacy spelling of:
@@ -1050,7 +1050,7 @@ BUILTIN_SIL_OPERATION(CreateAsyncTaskInGroupWithExecutor,
10501050
/// Int, // flags
10511051
/// Builtin.RawPointer, // group
10521052
/// Builtin.Executor, // executor
1053-
/// @escaping () async throws -> Void // function
1053+
/// sending @escaping () async throws -> Void // function
10541054
/// ) -> Builtin.NativeObject
10551055
///
10561056
/// Legacy spelling of:

lib/AST/Builtins.cpp

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

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

716721
template <class G>
@@ -1540,18 +1545,20 @@ static ValueDecl *getCreateTask(ASTContext &ctx, Identifier id) {
15401545
return getBuiltinFunction(
15411546
ctx, id, _thin, _generics(_unrestricted, _conformsToDefaults(0)),
15421547
_parameters(
1543-
_label("flags", _swiftInt),
1544-
_label("initialSerialExecutor", _defaulted(_optional(_executor), _nil)),
1545-
_label("taskGroup", _defaulted(_optional(_rawPointer), _nil)),
1546-
_label("initialTaskExecutor", _defaulted(_optional(_executor), _nil)),
1547-
_label("initialTaskExecutorConsuming",
1548+
_label("flags", _swiftInt),
1549+
_label("initialSerialExecutor",
1550+
_defaulted(_optional(_executor), _nil)),
1551+
_label("taskGroup", _defaulted(_optional(_rawPointer), _nil)),
1552+
_label("initialTaskExecutor", _defaulted(_optional(_executor), _nil)),
1553+
_label("initialTaskExecutorConsuming",
15481554
_defaulted(_consuming(_optional(_bincompatType(
15491555
/*if*/ taskExecutorIsAvailable,
15501556
_existential(_taskExecutor),
15511557
/*else*/ _executor))),
15521558
_nil)),
1553-
_label("operation", _function(_async(_throws(_sendable(_thick))),
1554-
_typeparam(0), _parameters()))),
1559+
_label("operation",
1560+
_sending(_function(_async(_throws(_thick)), _typeparam(0),
1561+
_parameters())))),
15551562
_tuple(_nativeObject, _rawPointer));
15561563
}
15571564

@@ -1562,18 +1569,19 @@ static ValueDecl *getCreateDiscardingTask(ASTContext &ctx, Identifier id) {
15621569
return getBuiltinFunction(
15631570
ctx, id, _thin,
15641571
_parameters(
1565-
_label("flags", _swiftInt),
1566-
_label("initialSerialExecutor", _defaulted(_optional(_executor), _nil)),
1567-
_label("taskGroup", _defaulted(_optional(_rawPointer), _nil)),
1568-
_label("initialTaskExecutor", _defaulted(_optional(_executor), _nil)),
1569-
_label("initialTaskExecutorConsuming",
1570-
_defaulted(_consuming(_optional(_bincompatType(
1571-
/*if*/ taskExecutorIsAvailable,
1572-
_existential(_taskExecutor),
1573-
/*else*/ _executor))),
1574-
_nil)),
1575-
_label("operation", _function(_async(_throws(_sendable(_thick))),
1576-
_void, _parameters()))),
1572+
_label("flags", _swiftInt),
1573+
_label("initialSerialExecutor",
1574+
_defaulted(_optional(_executor), _nil)),
1575+
_label("taskGroup", _defaulted(_optional(_rawPointer), _nil)),
1576+
_label("initialTaskExecutor", _defaulted(_optional(_executor), _nil)),
1577+
_label("initialTaskExecutorConsuming",
1578+
_defaulted(_consuming(_optional(_bincompatType(
1579+
/*if*/ taskExecutorIsAvailable,
1580+
_existential(_taskExecutor),
1581+
/*else*/ _executor))),
1582+
_nil)),
1583+
_label("operation", _sending(_function(_async(_throws(_thick)), _void,
1584+
_parameters())))),
15771585
_tuple(_nativeObject, _rawPointer));
15781586
}
15791587

@@ -1591,16 +1599,25 @@ static ValueDecl *getCreateAsyncTask(ASTContext &ctx, Identifier id,
15911599
if (withTaskExecutor) {
15921600
builder.addParameter(makeConcrete(ctx.TheExecutorType)); // executor
15931601
}
1594-
auto extInfo = ASTExtInfoBuilder().withAsync().withThrows()
1595-
.withSendable(true).build();
1602+
1603+
bool areSendingArgsEnabled =
1604+
ctx.LangOpts.hasFeature(Feature::SendingArgsAndResults);
1605+
1606+
auto extInfo = ASTExtInfoBuilder()
1607+
.withAsync()
1608+
.withThrows()
1609+
.withSendable(!areSendingArgsEnabled)
1610+
.build();
15961611
Type operationResultType;
15971612
if (isDiscarding) {
15981613
operationResultType = TupleType::getEmpty(ctx); // ()
15991614
} else {
16001615
operationResultType = makeGenericParam().build(builder); // <T>
16011616
}
1602-
builder.addParameter(makeConcrete(
1603-
FunctionType::get({}, operationResultType, extInfo))); // operation
1617+
builder.addParameter(
1618+
makeConcrete(FunctionType::get({}, operationResultType, extInfo)),
1619+
ParamSpecifier::Default,
1620+
areSendingArgsEnabled /*isSending*/); // operation
16041621
builder.setResult(makeConcrete(getAsyncTaskAndContextType(ctx)));
16051622
return builder.build(id);
16061623
}

lib/SIL/Verifier/SILVerifier.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2394,8 +2394,12 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
23942394
}
23952395
auto fnType = requireObjectType(SILFunctionType, arguments[5],
23962396
"result of createAsyncTask");
2397-
auto expectedExtInfo =
2398-
SILExtInfoBuilder().withAsync(true).withSendable(true).build();
2397+
bool haveSending =
2398+
F.getASTContext().LangOpts.hasFeature(Feature::SendingArgsAndResults);
2399+
auto expectedExtInfo = SILExtInfoBuilder()
2400+
.withAsync(true)
2401+
.withSendable(!haveSending)
2402+
.build();
23992403
require(fnType->getExtInfo().isEqualTo(expectedExtInfo, /*clang types*/true),
24002404
"function argument to createAsyncTask has incorrect ext info");
24012405
// 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
@@ -1630,11 +1630,13 @@ static ManagedValue emitCreateAsyncTask(SILGenFunction &SGF, SILLocation loc,
16301630

16311631
auto &&fnArg = nextArg();
16321632

1633+
bool hasSending = ctx.LangOpts.hasFeature(Feature::SendingArgsAndResults);
1634+
16331635
auto extInfo =
16341636
ASTExtInfoBuilder()
16351637
.withAsync()
16361638
.withThrows()
1637-
.withSendable(true)
1639+
.withSendable(!hasSending)
16381640
.withRepresentation(GenericFunctionType::Representation::Swift)
16391641
.build();
16401642

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

17641768
using Param = FunctionType::Param;
17651769
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
@@ -1849,11 +1849,23 @@ class PartitionOpTranslator {
18491849
translateSILMultiAssign(applyResults, pai->getOperandValues());
18501850
}
18511851

1852+
void translateCreateAsyncTask(BuiltinInst *bi) {
1853+
if (auto value = tryToTrackValue(bi->getOperand(1))) {
1854+
builder.addRequire(value->getRepresentative().getValue());
1855+
builder.addTransfer(value->getRepresentative().getValue(),
1856+
&bi->getAllOperands()[1]);
1857+
}
1858+
}
1859+
18521860
void translateSILBuiltin(BuiltinInst *bi) {
18531861
if (auto kind = bi->getBuiltinKind()) {
18541862
if (kind == BuiltinValueKind::StartAsyncLetWithLocalBuffer) {
18551863
return translateAsyncLetStart(bi);
18561864
}
1865+
1866+
if (kind == BuiltinValueKind::CreateAsyncTask) {
1867+
return translateCreateAsyncTask(bi);
1868+
}
18571869
}
18581870

18591871
// 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)