Skip to content

Commit 68eea8a

Browse files
committed
[TaskToThread] No unstructured tasks.
In this mode, the following are disabled: - task creation - global actors - MainActor - custom executors
1 parent b03904d commit 68eea8a

11 files changed

+362
-4
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6375,5 +6375,17 @@ NOTE(candidate_result_requires_explicit_coercion,none,
63756375
"loss of generic requirements",
63766376
(Type))
63776377

6378+
ERROR(concurrency_task_to_thread_model_custom_executor,none,
6379+
"custom executors are not permitted within %0", (StringRef))
6380+
ERROR(concurrency_task_to_thread_model_async_main,none,
6381+
"async main functions are not permitted within %0", (StringRef))
6382+
ERROR(concurrency_task_to_thread_model_main_actor,none,
6383+
"MainActor is not permitted within %0", (StringRef))
6384+
ERROR(concurrency_task_to_thread_model_global_actor,none,
6385+
"globalActor is not permitted within %0", (StringRef))
6386+
ERROR(concurrency_task_to_thread_model_global_actor_annotation,none,
6387+
"annotating a type with a global actor %0 is not permitted within %1",
6388+
(TypeRepr*, StringRef))
6389+
63786390
#define UNDEFINE_DIAGNOSTIC_MACROS
63796391
#include "DefineDiagnosticMacros.h"

lib/Sema/TypeCheckAttr.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2335,6 +2335,14 @@ SynthesizeMainFunctionRequest::evaluate(Evaluator &evaluator,
23352335
auto where = ExportContext::forDeclSignature(D);
23362336
diagnoseDeclAvailability(mainFunction, attr->getRange(), nullptr, where, None);
23372337

2338+
if (mainFunction->hasAsync() &&
2339+
context.LangOpts.isConcurrencyModelTaskToThread() &&
2340+
!AvailableAttr::isUnavailable(mainFunction)) {
2341+
mainFunction->diagnose(diag::concurrency_task_to_thread_model_async_main,
2342+
"task-to-thread concurrency model");
2343+
return nullptr;
2344+
}
2345+
23382346
auto *const func = FuncDecl::createImplicit(
23392347
context, StaticSpellingKind::KeywordStatic,
23402348
DeclName(context, DeclBaseName(context.Id_MainEntryPoint),
@@ -3307,6 +3315,15 @@ void AttributeChecker::visitFrozenAttr(FrozenAttr *attr) {
33073315
}
33083316
}
33093317

3318+
/// Determine whether this is the main actor type.
3319+
/// FIXME: the diagnostics engine and TypeCheckConcurrency both have a copy of
3320+
/// this
3321+
static bool isMainActor(NominalTypeDecl *nominal) {
3322+
return nominal->getName().is("MainActor") &&
3323+
nominal->getParentModule()->getName() ==
3324+
nominal->getASTContext().Id_Concurrency;
3325+
}
3326+
33103327
void AttributeChecker::visitCustomAttr(CustomAttr *attr) {
33113328
auto dc = D->getDeclContext();
33123329

@@ -3342,6 +3359,14 @@ void AttributeChecker::visitCustomAttr(CustomAttr *attr) {
33423359
return;
33433360
}
33443361

3362+
if (isMainActor(nominal) && Ctx.LangOpts.isConcurrencyModelTaskToThread() &&
3363+
!AvailableAttr::isUnavailable(D)) {
3364+
Ctx.Diags.diagnose(attr->getLocation(),
3365+
diag::concurrency_task_to_thread_model_main_actor,
3366+
"task-to-thread concurrency model");
3367+
return;
3368+
}
3369+
33453370
// If the nominal type is a property wrapper type, we can be delegating
33463371
// through a property.
33473372
if (nominal->getAttrs().hasAttribute<PropertyWrapperAttr>()) {
@@ -6025,6 +6050,15 @@ void AttributeChecker::visitGlobalActorAttr(GlobalActorAttr *attr) {
60256050
if (!nominal)
60266051
return; // already diagnosed
60276052

6053+
auto &context = nominal->getASTContext();
6054+
if (context.LangOpts.isConcurrencyModelTaskToThread() &&
6055+
!AvailableAttr::isUnavailable(nominal)) {
6056+
context.Diags.diagnose(attr->getLocation(),
6057+
diag::concurrency_task_to_thread_model_global_actor,
6058+
"task-to-thread concurrency model");
6059+
return;
6060+
}
6061+
60286062
(void)nominal->isGlobalActor();
60296063
}
60306064

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -188,9 +188,18 @@ bool IsDefaultActorRequest::evaluate(
188188
// If we synthesized the unownedExecutor property, we should've
189189
// added a semantics attribute to it (if it was actually a default
190190
// actor).
191-
if (auto executorProperty = classDecl->getUnownedExecutorProperty())
192-
return executorProperty->getAttrs()
193-
.hasSemanticsAttr(SEMANTICS_DEFAULT_ACTOR);
191+
if (auto executorProperty = classDecl->getUnownedExecutorProperty()) {
192+
bool isDefaultActor =
193+
executorProperty->getAttrs().hasSemanticsAttr(SEMANTICS_DEFAULT_ACTOR);
194+
if (!isDefaultActor &&
195+
classDecl->getASTContext().LangOpts.isConcurrencyModelTaskToThread() &&
196+
!AvailableAttr::isUnavailable(classDecl)) {
197+
classDecl->diagnose(
198+
diag::concurrency_task_to_thread_model_custom_executor,
199+
"task-to-thread concurrency model");
200+
}
201+
return isDefaultActor;
202+
}
194203

195204
return true;
196205
}

lib/Sema/TypeCheckType.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2332,8 +2332,16 @@ TypeResolver::resolveAttributedType(TypeAttributes &attrs, TypeRepr *repr,
23322332
// Diagnose custom attributes that haven't been processed yet.
23332333
for (auto customAttr : attrs.getCustomAttrs()) {
23342334
// If this was the global actor we matched, ignore it.
2335-
if (globalActorAttr == customAttr)
2335+
if (globalActorAttr == customAttr) {
2336+
Decl *decl = nullptr;
2337+
if (getASTContext().LangOpts.isConcurrencyModelTaskToThread() &&
2338+
(decl = getDeclContext()->getAsDecl()) &&
2339+
!AvailableAttr::isUnavailable(decl))
2340+
diagnose(customAttr->getLocation(),
2341+
diag::concurrency_task_to_thread_model_global_actor_annotation,
2342+
customAttr->getTypeRepr(), "task-to-thread concurrency model");
23362343
continue;
2344+
}
23372345

23382346
// If this attribute was marked invalid, ignore it.
23392347
if (customAttr->isInvalid())

stdlib/public/Concurrency/MainActor.swift

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,36 @@
1212

1313
import Swift
1414

15+
#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
16+
@available(SwiftStdlib 5.1, *)
17+
@available(*, unavailable, message: "Unavailable in task-to-thread concurrency model")
18+
@globalActor public final actor MainActor: GlobalActor {
19+
public static let shared = MainActor()
20+
21+
@inlinable
22+
public nonisolated var unownedExecutor: UnownedSerialExecutor {
23+
#if compiler(>=5.5) && $BuiltinBuildMainExecutor
24+
return UnownedSerialExecutor(Builtin.buildMainActorExecutorRef())
25+
#else
26+
fatalError("Swift compiler is incompatible with this SDK version")
27+
#endif
28+
}
29+
30+
@inlinable
31+
public static var sharedUnownedExecutor: UnownedSerialExecutor {
32+
#if compiler(>=5.5) && $BuiltinBuildMainExecutor
33+
return UnownedSerialExecutor(Builtin.buildMainActorExecutorRef())
34+
#else
35+
fatalError("Swift compiler is incompatible with this SDK version")
36+
#endif
37+
}
38+
39+
@inlinable
40+
public nonisolated func enqueue(_ job: UnownedJob) {
41+
_enqueueOnMain(job)
42+
}
43+
}
44+
#else
1545
/// A singleton actor whose executor is equivalent to the main
1646
/// dispatch queue.
1747
@available(SwiftStdlib 5.1, *)
@@ -41,7 +71,9 @@ import Swift
4171
_enqueueOnMain(job)
4272
}
4373
}
74+
#endif
4475

76+
#if !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
4577
@available(SwiftStdlib 5.1, *)
4678
extension MainActor {
4779
/// Execute the given body closure on the main actor.
@@ -66,3 +98,4 @@ extension MainActor {
6698
return try await body()
6799
}
68100
}
101+
#endif

stdlib/public/Concurrency/SourceCompatibilityShims.swift

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,17 @@ extension Task where Success == Never, Failure == Never {
7575

7676
@available(SwiftStdlib 5.1, *)
7777
extension Task where Failure == Error {
78+
#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
79+
@discardableResult
80+
@_alwaysEmitIntoClient
81+
@available(*, unavailable, message: "Unavailable in task-to-thread concurrency model")
82+
public static func runDetached(
83+
priority: TaskPriority? = nil,
84+
operation: __owned @Sendable @escaping () async throws -> Success
85+
) -> Task<Success, Failure> {
86+
fatalError("Unavailable in task-to-thread concurrency model")
87+
}
88+
#else
7889
@discardableResult
7990
@_alwaysEmitIntoClient
8091
@available(*, deprecated, message: "`Task.runDetached` was replaced by `Task.detached` and will be removed shortly.")
@@ -84,8 +95,21 @@ extension Task where Failure == Error {
8495
) -> Task<Success, Failure> {
8596
detached(priority: priority, operation: operation)
8697
}
98+
#endif
8799
}
88100

101+
#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
102+
@discardableResult
103+
@available(SwiftStdlib 5.1, *)
104+
@available(*, unavailable, message: "Unavailable in task-to-thread concurrency model")
105+
@_alwaysEmitIntoClient
106+
public func detach<T>(
107+
priority: TaskPriority? = nil,
108+
operation: __owned @Sendable @escaping () async -> T
109+
) -> Task<T, Never> {
110+
fatalError("Unavailable in task-to-thread concurrency model")
111+
}
112+
#else
89113
@discardableResult
90114
@available(SwiftStdlib 5.1, *)
91115
@available(*, deprecated, message: "`detach` was replaced by `Task.detached` and will be removed shortly.")
@@ -96,7 +120,20 @@ public func detach<T>(
96120
) -> Task<T, Never> {
97121
Task.detached(priority: priority, operation: operation)
98122
}
123+
#endif
99124

125+
#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
126+
@discardableResult
127+
@available(SwiftStdlib 5.1, *)
128+
@available(*, unavailable, message: "Unavailable in task-to-thread concurrency model")
129+
@_alwaysEmitIntoClient
130+
public func detach<T>(
131+
priority: TaskPriority? = nil,
132+
operation: __owned @Sendable @escaping () async throws -> T
133+
) -> Task<T, Error> {
134+
fatalError("Unavailable in task-to-thread concurrency model")
135+
}
136+
#else
100137
@discardableResult
101138
@available(SwiftStdlib 5.1, *)
102139
@available(*, deprecated, message: "`detach` was replaced by `Task.detached` and will be removed shortly.")
@@ -107,7 +144,20 @@ public func detach<T>(
107144
) -> Task<T, Error> {
108145
Task.detached(priority: priority, operation: operation)
109146
}
147+
#endif
110148

149+
#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
150+
@discardableResult
151+
@available(SwiftStdlib 5.1, *)
152+
@available(*, unavailable, message: "Unavailable in task-to-thread concurrency model")
153+
@_alwaysEmitIntoClient
154+
public func asyncDetached<T>(
155+
priority: TaskPriority? = nil,
156+
@_implicitSelfCapture operation: __owned @Sendable @escaping () async -> T
157+
) -> Task<T, Never> {
158+
fatalError("Unavailable in task-to-thread concurrency model")
159+
}
160+
#else
111161
@discardableResult
112162
@available(SwiftStdlib 5.1, *)
113163
@available(*, deprecated, message: "`asyncDetached` was replaced by `Task.detached` and will be removed shortly.")
@@ -118,7 +168,20 @@ public func asyncDetached<T>(
118168
) -> Task<T, Never> {
119169
return Task.detached(priority: priority, operation: operation)
120170
}
171+
#endif
121172

173+
#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
174+
@discardableResult
175+
@available(SwiftStdlib 5.1, *)
176+
@available(*, unavailable, message: "Unavailable in task-to-thread concurrency model")
177+
@_alwaysEmitIntoClient
178+
public func asyncDetached<T>(
179+
priority: TaskPriority? = nil,
180+
@_implicitSelfCapture operation: __owned @Sendable @escaping () async throws -> T
181+
) -> Task<T, Error> {
182+
fatalError("Unavailable in task-to-thread concurrency model")
183+
}
184+
#else
122185
@discardableResult
123186
@available(SwiftStdlib 5.1, *)
124187
@available(*, deprecated, message: "`asyncDetached` was replaced by `Task.detached` and will be removed shortly.")
@@ -129,7 +192,20 @@ public func asyncDetached<T>(
129192
) -> Task<T, Error> {
130193
return Task.detached(priority: priority, operation: operation)
131194
}
195+
#endif
132196

197+
#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
198+
@available(SwiftStdlib 5.1, *)
199+
@available(*, unavailable, message: "Unavailable in task-to-thread concurrency model")
200+
@discardableResult
201+
@_alwaysEmitIntoClient
202+
public func async<T>(
203+
priority: TaskPriority? = nil,
204+
@_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping () async -> T
205+
) -> Task<T, Never> {
206+
fatalError("Unavailable in task-to-thread concurrency model")
207+
}
208+
#else
133209
@available(SwiftStdlib 5.1, *)
134210
@available(*, deprecated, message: "`async` was replaced by `Task.init` and will be removed shortly.")
135211
@discardableResult
@@ -140,7 +216,20 @@ public func async<T>(
140216
) -> Task<T, Never> {
141217
.init(priority: priority, operation: operation)
142218
}
219+
#endif
143220

221+
#if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
222+
@available(SwiftStdlib 5.1, *)
223+
@available(*, unavailable, message: "Unavailable in task-to-thread concurrency model")
224+
@discardableResult
225+
@_alwaysEmitIntoClient
226+
public func async<T>(
227+
priority: TaskPriority? = nil,
228+
@_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping () async throws -> T
229+
) -> Task<T, Error> {
230+
fatalError("Unavailable in task-to-thread concurrency model")
231+
}
232+
#else
144233
@available(SwiftStdlib 5.1, *)
145234
@available(*, deprecated, message: "`async` was replaced by `Task.init` and will be removed shortly.")
146235
@discardableResult
@@ -151,6 +240,7 @@ public func async<T>(
151240
) -> Task<T, Error> {
152241
.init(priority: priority, operation: operation)
153242
}
243+
#endif
154244

155245
@available(SwiftStdlib 5.1, *)
156246
extension Task where Success == Never, Failure == Never {

0 commit comments

Comments
 (0)