Skip to content

Commit 74944a6

Browse files
authored
Merge pull request #74239 from gottesmm/taskinit-sending
[sending] Mark Task.init, Task.detached and friends as taking a sending closure instead of a __owned @sendable
2 parents 4afac73 + 3685cdd commit 74944a6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+1508
-395
lines changed

docs/ReferenceGuides/UnderscoredAttributes.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -591,11 +591,14 @@ class C {
591591

592592
(Note that it is "inherit", not "inherits", unlike below.)
593593

594-
Marks that a `@Sendable async` closure argument should inherit the actor
595-
context (i.e. what actor it should be run on) based on the declaration site
596-
of the closure. This is different from the typical behavior, where the closure
597-
may be runnable anywhere unless its type specifically declares that it will
598-
run on a specific actor.
594+
Marks that a `@Sendable async` or `sendable async` closure argument should
595+
inherit the actor context (i.e. what actor it should be run on) based on the
596+
declaration site of the closure rather than be non-Sendable. This does not do
597+
anything if the closure is synchronous.
598+
599+
DISCUSSION: The reason why this does nothing when the closure is synchronous is
600+
since it does not have the ability to hop to the appropriate executor before it
601+
is run, so we may create concurrency errors.
599602

600603
## `@_inheritsConvenienceInitializers`
601604

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:

include/swift/AST/Expr.h

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ class alignas(8) Expr : public ASTAllocated<Expr> {
266266
Kind : 2
267267
);
268268

269-
SWIFT_INLINE_BITFIELD(ClosureExpr, AbstractClosureExpr, 1+1+1+1,
269+
SWIFT_INLINE_BITFIELD(ClosureExpr, AbstractClosureExpr, 1+1+1+1+1,
270270
/// True if closure parameters were synthesized from anonymous closure
271271
/// variables.
272272
HasAnonymousClosureVars : 1,
@@ -281,7 +281,10 @@ class alignas(8) Expr : public ASTAllocated<Expr> {
281281

282282
/// True if this closure's actor isolation behavior was determined by an
283283
/// \c \@preconcurrency declaration.
284-
IsolatedByPreconcurrency : 1
284+
IsolatedByPreconcurrency : 1,
285+
286+
/// True if this is a closure literal that is passed to a sending parameter.
287+
IsPassedToSendingParameter : 1
285288
);
286289

287290
SWIFT_INLINE_BITFIELD_FULL(BindOptionalExpr, Expr, 16,
@@ -4139,6 +4142,7 @@ class ClosureExpr : public AbstractClosureExpr {
41394142
Bits.ClosureExpr.HasAnonymousClosureVars = false;
41404143
Bits.ClosureExpr.ImplicitSelfCapture = false;
41414144
Bits.ClosureExpr.InheritActorContext = false;
4145+
Bits.ClosureExpr.IsPassedToSendingParameter = false;
41424146
}
41434147

41444148
SourceRange getSourceRange() const;
@@ -4194,6 +4198,16 @@ class ClosureExpr : public AbstractClosureExpr {
41944198
Bits.ClosureExpr.IsolatedByPreconcurrency = value;
41954199
}
41964200

4201+
/// Whether the closure is a closure literal that is passed to a sending
4202+
/// parameter.
4203+
bool isPassedToSendingParameter() const {
4204+
return Bits.ClosureExpr.IsPassedToSendingParameter;
4205+
}
4206+
4207+
void setIsPassedToSendingParameter(bool value = true) {
4208+
Bits.ClosureExpr.IsPassedToSendingParameter = value;
4209+
}
4210+
41974211
/// Determine whether this closure expression has an
41984212
/// explicitly-specified result type.
41994213
bool hasExplicitResultType() const { return ArrowLoc.isValid(); }

include/swift/AST/Types.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3832,6 +3832,7 @@ struct ParameterListInfo {
38323832
SmallBitVector implicitSelfCapture;
38333833
SmallBitVector inheritActorContext;
38343834
SmallBitVector variadicGenerics;
3835+
SmallBitVector isPassedToSending;
38353836

38363837
public:
38373838
ParameterListInfo() { }
@@ -3863,6 +3864,9 @@ struct ParameterListInfo {
38633864

38643865
bool isVariadicGenericParameter(unsigned paramIdx) const;
38653866

3867+
/// Returns true if this is a sending parameter.
3868+
bool isPassedToSendingParameter(unsigned paramIdx) const;
3869+
38663870
/// Retrieve the number of non-defaulted parameters.
38673871
unsigned numNonDefaultedParameters() const {
38683872
return defaultArguments.count();

include/swift/SILOptimizer/Utils/PartitionUtils.h

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1154,6 +1154,28 @@ struct PartitionOpEvaluator {
11541154
}
11551155

11561156
private:
1157+
bool isConvertFunctionFromSendableType(SILValue equivalenceClassRep) const {
1158+
SILValue valueToTest = equivalenceClassRep;
1159+
while (true) {
1160+
if (auto *i = dyn_cast<ThinToThickFunctionInst>(valueToTest)) {
1161+
valueToTest = i->getOperand();
1162+
continue;
1163+
}
1164+
if (auto *i = dyn_cast<ConvertEscapeToNoEscapeInst>(valueToTest)) {
1165+
valueToTest = i->getOperand();
1166+
continue;
1167+
}
1168+
break;
1169+
}
1170+
1171+
auto *cvi = dyn_cast<ConvertFunctionInst>(valueToTest);
1172+
if (!cvi)
1173+
return false;
1174+
1175+
return cvi->getOperand()->getType().isSendable(
1176+
equivalenceClassRep->getFunction());
1177+
}
1178+
11571179
// Private helper that squelches the error if our transfer instruction and our
11581180
// use have the same isolation.
11591181
void handleLocalUseAfterTransferHelper(const PartitionOp &op, Element elt,
@@ -1166,12 +1188,13 @@ struct PartitionOpEvaluator {
11661188
return;
11671189
}
11681190

1169-
// If we have a temporary that is initialized with an unsafe nonisolated
1170-
// value... squelch the error like if we were that value.
1171-
//
1172-
// TODO: This goes away with opaque values.
11731191
if (SILValue equivalenceClassRep =
11741192
getRepresentative(transferringOp->get())) {
1193+
1194+
// If we have a temporary that is initialized with an unsafe nonisolated
1195+
// value... squelch the error like if we were that value.
1196+
//
1197+
// TODO: This goes away with opaque values.
11751198
if (auto *asi = dyn_cast<AllocStackInst>(equivalenceClassRep)) {
11761199
if (SILValue value = getInitOfTemporaryAllocStack(asi)) {
11771200
if (auto elt = getElement(value)) {
@@ -1182,6 +1205,11 @@ struct PartitionOpEvaluator {
11821205
}
11831206
}
11841207
}
1208+
1209+
// See if we have a convert function from a `@Sendable` type. In this
1210+
// case, we want to squelch the error.
1211+
if (isConvertFunctionFromSendableType(equivalenceClassRep))
1212+
return;
11851213
}
11861214

11871215
// If our instruction does not have any isolation info associated with it,
@@ -1206,12 +1234,12 @@ struct PartitionOpEvaluator {
12061234
const PartitionOp &op, Element elt,
12071235
SILDynamicMergedIsolationInfo dynamicMergedIsolationInfo) const {
12081236
if (shouldTryToSquelchErrors()) {
1209-
// If we have a temporary that is initialized with an unsafe nonisolated
1210-
// value... squelch the error like if we were that value.
1211-
//
1212-
// TODO: This goes away with opaque values.
12131237
if (SILValue equivalenceClassRep =
12141238
getRepresentative(op.getSourceOp()->get())) {
1239+
// If we have a temporary that is initialized with an unsafe nonisolated
1240+
// value... squelch the error like if we were that value.
1241+
//
1242+
// TODO: This goes away with opaque values.
12151243
if (auto *asi = dyn_cast<AllocStackInst>(equivalenceClassRep)) {
12161244
if (SILValue value = getInitOfTemporaryAllocStack(asi)) {
12171245
if (auto elt = getElement(value)) {
@@ -1222,6 +1250,11 @@ struct PartitionOpEvaluator {
12221250
}
12231251
}
12241252
}
1253+
1254+
// See if we have a convert function from a `@Sendable` type. In this
1255+
// case, we want to squelch the error.
1256+
if (isConvertFunctionFromSendableType(equivalenceClassRep))
1257+
return;
12251258
}
12261259
}
12271260

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
}

0 commit comments

Comments
 (0)