Skip to content

Commit 4d6af20

Browse files
authored
Merge pull request #74608 from gottesmm/release/6.0-task
[6.0][sending] Add support for Task.init and friends and TaskGroup and friends to take sending closures
2 parents c6e3c71 + 1eaf605 commit 4d6af20

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

+1509
-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
@@ -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:

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,
@@ -4126,6 +4129,7 @@ class ClosureExpr : public AbstractClosureExpr {
41264129
Bits.ClosureExpr.HasAnonymousClosureVars = false;
41274130
Bits.ClosureExpr.ImplicitSelfCapture = false;
41284131
Bits.ClosureExpr.InheritActorContext = false;
4132+
Bits.ClosureExpr.IsPassedToSendingParameter = false;
41294133
}
41304134

41314135
SourceRange getSourceRange() const;
@@ -4181,6 +4185,16 @@ class ClosureExpr : public AbstractClosureExpr {
41814185
Bits.ClosureExpr.IsolatedByPreconcurrency = value;
41824186
}
41834187

4188+
/// Whether the closure is a closure literal that is passed to a sending
4189+
/// parameter.
4190+
bool isPassedToSendingParameter() const {
4191+
return Bits.ClosureExpr.IsPassedToSendingParameter;
4192+
}
4193+
4194+
void setIsPassedToSendingParameter(bool value = true) {
4195+
Bits.ClosureExpr.IsPassedToSendingParameter = value;
4196+
}
4197+
41844198
/// Determine whether this closure expression has an
41854199
/// explicitly-specified result type.
41864200
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
@@ -3837,6 +3837,7 @@ struct ParameterListInfo {
38373837
SmallBitVector implicitSelfCapture;
38383838
SmallBitVector inheritActorContext;
38393839
SmallBitVector variadicGenerics;
3840+
SmallBitVector isPassedToSending;
38403841

38413842
public:
38423843
ParameterListInfo() { }
@@ -3868,6 +3869,9 @@ struct ParameterListInfo {
38683869

38693870
bool isVariadicGenericParameter(unsigned paramIdx) const;
38703871

3872+
/// Returns true if this is a sending parameter.
3873+
bool isPassedToSendingParameter(unsigned paramIdx) const;
3874+
38713875
/// Retrieve the number of non-defaulted parameters.
38723876
unsigned numNonDefaultedParameters() const {
38733877
return defaultArguments.count();

include/swift/SILOptimizer/Utils/PartitionUtils.h

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1176,6 +1176,28 @@ struct PartitionOpEvaluator {
11761176
}
11771177

11781178
private:
1179+
bool isConvertFunctionFromSendableType(SILValue equivalenceClassRep) const {
1180+
SILValue valueToTest = equivalenceClassRep;
1181+
while (true) {
1182+
if (auto *i = dyn_cast<ThinToThickFunctionInst>(valueToTest)) {
1183+
valueToTest = i->getOperand();
1184+
continue;
1185+
}
1186+
if (auto *i = dyn_cast<ConvertEscapeToNoEscapeInst>(valueToTest)) {
1187+
valueToTest = i->getOperand();
1188+
continue;
1189+
}
1190+
break;
1191+
}
1192+
1193+
auto *cvi = dyn_cast<ConvertFunctionInst>(valueToTest);
1194+
if (!cvi)
1195+
return false;
1196+
1197+
return cvi->getOperand()->getType().isSendable(
1198+
equivalenceClassRep->getFunction());
1199+
}
1200+
11791201
// Private helper that squelches the error if our transfer instruction and our
11801202
// use have the same isolation.
11811203
void handleLocalUseAfterTransferHelper(const PartitionOp &op, Element elt,
@@ -1188,12 +1210,13 @@ struct PartitionOpEvaluator {
11881210
return;
11891211
}
11901212

1191-
// If we have a temporary that is initialized with an unsafe nonisolated
1192-
// value... squelch the error like if we were that value.
1193-
//
1194-
// TODO: This goes away with opaque values.
11951213
if (SILValue equivalenceClassRep =
11961214
getRepresentative(transferringOp->get())) {
1215+
1216+
// If we have a temporary that is initialized with an unsafe nonisolated
1217+
// value... squelch the error like if we were that value.
1218+
//
1219+
// TODO: This goes away with opaque values.
11971220
if (auto *asi = dyn_cast<AllocStackInst>(equivalenceClassRep)) {
11981221
if (SILValue value = getInitOfTemporaryAllocStack(asi)) {
11991222
if (auto elt = getElement(value)) {
@@ -1204,6 +1227,11 @@ struct PartitionOpEvaluator {
12041227
}
12051228
}
12061229
}
1230+
1231+
// See if we have a convert function from a `@Sendable` type. In this
1232+
// case, we want to squelch the error.
1233+
if (isConvertFunctionFromSendableType(equivalenceClassRep))
1234+
return;
12071235
}
12081236

12091237
// If our instruction does not have any isolation info associated with it,
@@ -1228,12 +1256,12 @@ struct PartitionOpEvaluator {
12281256
const PartitionOp &op, Element elt,
12291257
SILDynamicMergedIsolationInfo dynamicMergedIsolationInfo) const {
12301258
if (shouldTryToSquelchErrors()) {
1231-
// If we have a temporary that is initialized with an unsafe nonisolated
1232-
// value... squelch the error like if we were that value.
1233-
//
1234-
// TODO: This goes away with opaque values.
12351259
if (SILValue equivalenceClassRep =
12361260
getRepresentative(op.getSourceOp()->get())) {
1261+
// If we have a temporary that is initialized with an unsafe nonisolated
1262+
// value... squelch the error like if we were that value.
1263+
//
1264+
// TODO: This goes away with opaque values.
12371265
if (auto *asi = dyn_cast<AllocStackInst>(equivalenceClassRep)) {
12381266
if (SILValue value = getInitOfTemporaryAllocStack(asi)) {
12391267
if (auto elt = getElement(value)) {
@@ -1244,6 +1272,11 @@ struct PartitionOpEvaluator {
12441272
}
12451273
}
12461274
}
1275+
1276+
// See if we have a convert function from a `@Sendable` type. In this
1277+
// case, we want to squelch the error.
1278+
if (isConvertFunctionFromSendableType(equivalenceClassRep))
1279+
return;
12471280
}
12481281
}
12491282

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
}

0 commit comments

Comments
 (0)