Skip to content

Commit c499475

Browse files
committedMar 18, 2025·
Sema: Implement adoption mode for AsyncCallerExecution
1 parent 2c7fb6a commit c499475

12 files changed

+534
-7
lines changed
 

‎include/swift/AST/DiagnosticEngine.h

+12-1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ class Type;
4444

4545
namespace swift {
4646
class ConstructorDecl;
47+
class ClosureExpr;
4748
class Decl;
4849
class DeclAttribute;
4950
class DiagnosticEngine;
@@ -900,7 +901,17 @@ namespace swift {
900901
InFlightDiagnostic &fixItInsertAfter(SourceLoc L, StringRef Str) {
901902
return fixItInsertAfter(L, "%0", {Str});
902903
}
903-
904+
905+
/// Add a fix-it suggesting to insert the given attribute at the given
906+
/// location.
907+
InFlightDiagnostic &fixItInsertAttribute(SourceLoc L,
908+
const DeclAttribute *Attr);
909+
910+
/// Add a fix-it suggesting to add the given attribute to the given
911+
/// closure.
912+
InFlightDiagnostic &fixItAddAttribute(const DeclAttribute *Attr,
913+
const ClosureExpr *E);
914+
904915
/// Add a token-based removal fix-it to the currently-active
905916
/// diagnostic.
906917
InFlightDiagnostic &fixItRemove(SourceRange R);

‎include/swift/AST/DiagnosticGroups.def

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ GROUP(DeprecatedDeclaration, "deprecated-declaration.md")
2626
GROUP(StrictMemorySafety, "strict-memory-safety.md")
2727
GROUP(UnknownWarningGroup, "unknown-warning-group.md")
2828
GROUP(PreconcurrencyImport, "preconcurrency-import.md")
29+
GROUP(AsyncCallerExecution, "async-caller-execution.md")
2930
GROUP(StrictLanguageFeatures, "strict-language-features.md")
3031
GROUP(ExistentialAny, "existential-any.md")
3132

‎include/swift/AST/DiagnosticsSema.def

+22
Original file line numberDiff line numberDiff line change
@@ -8389,6 +8389,28 @@ ERROR(invalid_function_conversion_with_non_sendable,none,
83898389
NOTE(type_does_not_conform_to_Sendable,none,
83908390
"type %0 does not conform to 'Sendable' protocol", (Type))
83918391

8392+
GROUPED_WARNING(
8393+
attr_execution_nonisolated_behavior_will_change_decl, AsyncCallerExecution,
8394+
none,
8395+
"feature '%0' will cause nonisolated async %kindbase1 to run on the "
8396+
"caller's actor; use %2 to preserve behavior",
8397+
(StringRef, const AbstractFunctionDecl *, DeclAttribute))
8398+
8399+
GROUPED_WARNING(
8400+
attr_execution_nonisolated_behavior_will_change_closure,
8401+
AsyncCallerExecution, none,
8402+
"feature '%0' will cause nonisolated async closure to run on the caller's "
8403+
"actor; use %1 to preserve behavior",
8404+
(StringRef, DeclAttribute))
8405+
8406+
GROUPED_WARNING(
8407+
attr_execution_nonisolated_behavior_will_change_typerepr,
8408+
AsyncCallerExecution, none,
8409+
"feature '%0' will cause nonisolated async function type to be treated as "
8410+
"specified to run on the caller's actor; use %1 to preserve "
8411+
"behavior",
8412+
(StringRef, DeclAttribute))
8413+
83928414
//===----------------------------------------------------------------------===//
83938415
// MARK: SwiftSettings
83948416
//===----------------------------------------------------------------------===//

‎include/swift/Basic/Features.def

+1-1
Original file line numberDiff line numberDiff line change
@@ -485,7 +485,7 @@ SUPPRESSIBLE_EXPERIMENTAL_FEATURE(ExecutionAttribute, false)
485485

486486
/// Functions with nonisolated isolation inherit their isolation from the
487487
/// calling context.
488-
EXPERIMENTAL_FEATURE(AsyncCallerExecution, false)
488+
ADOPTABLE_EXPERIMENTAL_FEATURE(AsyncCallerExecution, false)
489489

490490
/// Allow custom availability domains to be defined and referenced.
491491
SUPPRESSIBLE_EXPERIMENTAL_FEATURE(CustomAvailability, true)

‎lib/AST/DiagnosticEngine.cpp

+36
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,42 @@ InFlightDiagnostic &InFlightDiagnostic::fixItAddImport(StringRef ModuleName) {
398398
return *this;
399399
}
400400

401+
InFlightDiagnostic &
402+
InFlightDiagnostic::fixItInsertAttribute(SourceLoc L,
403+
const DeclAttribute *Attr) {
404+
return fixItInsert(L, "%0 ", {Attr});
405+
}
406+
407+
InFlightDiagnostic &
408+
InFlightDiagnostic::fixItAddAttribute(const DeclAttribute *Attr,
409+
const ClosureExpr *E) {
410+
ASSERT(!E->isImplicit());
411+
412+
SourceLoc insertionLoc;
413+
414+
if (auto *paramList = E->getParameters()) {
415+
// HACK: Don't set insertion loc to param list start loc if it's equal to
416+
// closure start loc (meaning it's implicit).
417+
// FIXME: Don't set the start loc of an implicit param list, or put an
418+
// isImplicit bit on ParameterList.
419+
if (paramList->getStartLoc() != E->getStartLoc()) {
420+
insertionLoc = paramList->getStartLoc();
421+
}
422+
}
423+
424+
if (insertionLoc.isInvalid()) {
425+
insertionLoc = E->getInLoc();
426+
}
427+
428+
if (insertionLoc.isValid()) {
429+
return fixItInsert(insertionLoc, "%0 ", {Attr});
430+
} else {
431+
insertionLoc = E->getBody()->getLBraceLoc();
432+
ASSERT(insertionLoc.isValid());
433+
return fixItInsertAfter(insertionLoc, " %0 in ", {Attr});
434+
}
435+
}
436+
401437
InFlightDiagnostic &InFlightDiagnostic::fixItExchange(SourceRange R1,
402438
SourceRange R2) {
403439
assert(IsActive && "Cannot modify an inactive diagnostic");
+177
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
//===-- Sema/AsyncCallerExecutionMigration.cpp ------------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2025 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
///
13+
/// \file
14+
/// This file implements code migration support for the `AsyncCallerExecution`
15+
/// feature.
16+
///
17+
//===----------------------------------------------------------------------===//
18+
19+
#include "AsyncCallerExecutionMigration.h"
20+
#include "swift/AST/ASTContext.h"
21+
#include "swift/AST/Decl.h"
22+
#include "swift/AST/DiagnosticsSema.h"
23+
#include "swift/AST/Expr.h"
24+
#include "swift/AST/TypeRepr.h"
25+
#include "swift/Basic/Assertions.h"
26+
#include "swift/Basic/Feature.h"
27+
#include "swift/Basic/TaggedUnion.h"
28+
#include "llvm/ADT/PointerUnion.h"
29+
30+
using namespace swift;
31+
32+
namespace {
33+
class AsyncCallerExecutionMigrationTarget {
34+
ASTContext &ctx;
35+
PointerUnion<ValueDecl *, AbstractClosureExpr *, FunctionTypeRepr *> node;
36+
TaggedUnion<ActorIsolation, FunctionTypeIsolation> isolation;
37+
38+
public:
39+
AsyncCallerExecutionMigrationTarget(ASTContext &ctx, ValueDecl *decl,
40+
ActorIsolation isolation)
41+
: ctx(ctx), node(decl), isolation(isolation) {}
42+
43+
AsyncCallerExecutionMigrationTarget(ASTContext &ctx,
44+
AbstractClosureExpr *closure,
45+
ActorIsolation isolation)
46+
: ctx(ctx), node(closure), isolation(isolation) {}
47+
48+
AsyncCallerExecutionMigrationTarget(ASTContext &ctx, FunctionTypeRepr *repr,
49+
FunctionTypeIsolation isolation)
50+
: ctx(ctx), node(repr), isolation(isolation) {}
51+
52+
/// Warns that the behavior of nonisolated async functions will change under
53+
/// `AsyncCallerExecution` and suggests `@execution(concurrent)` to preserve
54+
/// the current behavior.
55+
void diagnose() const;
56+
};
57+
} // end anonymous namespace
58+
59+
void AsyncCallerExecutionMigrationTarget::diagnose() const {
60+
const auto feature = Feature::AsyncCallerExecution;
61+
62+
ASSERT(node);
63+
ASSERT(ctx.LangOpts.getFeatureState(feature).isEnabledForAdoption());
64+
65+
AbstractFunctionDecl *functionDecl = nullptr;
66+
ClosureExpr *closure = nullptr;
67+
FunctionTypeRepr *functionRepr = nullptr;
68+
69+
if (auto *decl = node.dyn_cast<ValueDecl *>()) {
70+
// Diagnose only explicit nodes.
71+
if (decl->isImplicit()) {
72+
return;
73+
}
74+
75+
// Diagnose only functions.
76+
functionDecl = dyn_cast<AbstractFunctionDecl>(decl);
77+
if (!functionDecl) {
78+
return;
79+
}
80+
} else if (auto *anyClosure = node.dyn_cast<AbstractClosureExpr *>()) {
81+
// Diagnose only explicit nodes.
82+
if (anyClosure->isImplicit()) {
83+
return;
84+
}
85+
86+
// The only subclass that can be explicit is this one.
87+
closure = cast<ClosureExpr>(anyClosure);
88+
} else {
89+
functionRepr = node.get<FunctionTypeRepr *>();
90+
}
91+
92+
// The execution behavior changes only for nonisolated functions.
93+
{
94+
bool isNonisolated;
95+
if (functionRepr) {
96+
isNonisolated = isolation.get<FunctionTypeIsolation>().isNonIsolated();
97+
} else {
98+
auto isolation = this->isolation.get<ActorIsolation>();
99+
isNonisolated = isolation.isNonisolated() || isolation.isUnspecified();
100+
}
101+
102+
if (!isNonisolated) {
103+
return;
104+
}
105+
}
106+
107+
// If the intended behavior is specified explicitly, don't diagnose.
108+
{
109+
const DeclAttributes *attrs = nullptr;
110+
if (functionDecl) {
111+
attrs = &functionDecl->getAttrs();
112+
} else if (closure) {
113+
attrs = &closure->getAttrs();
114+
}
115+
116+
if (attrs && attrs->hasAttribute<ExecutionAttr>()) {
117+
return;
118+
}
119+
}
120+
121+
// The execution behavior changes only for async functions.
122+
{
123+
bool isAsync = false;
124+
if (functionDecl) {
125+
isAsync = functionDecl->hasAsync();
126+
} else if (closure) {
127+
isAsync = closure->isBodyAsync();
128+
} else {
129+
isAsync = functionRepr->isAsync();
130+
}
131+
132+
if (!isAsync) {
133+
return;
134+
}
135+
}
136+
137+
const ExecutionAttr attr(ExecutionKind::Concurrent, /*implicit=*/true);
138+
139+
const auto featureName = getFeatureName(feature);
140+
if (functionDecl) {
141+
ctx.Diags
142+
.diagnose(functionDecl->getLoc(),
143+
diag::attr_execution_nonisolated_behavior_will_change_decl,
144+
featureName, functionDecl, &attr)
145+
.fixItInsertAttribute(
146+
functionDecl->getAttributeInsertionLoc(/*forModifier=*/false),
147+
&attr);
148+
} else if (closure) {
149+
ctx.Diags
150+
.diagnose(closure->getLoc(),
151+
diag::attr_execution_nonisolated_behavior_will_change_closure,
152+
featureName, &attr)
153+
.fixItAddAttribute(&attr, closure);
154+
} else {
155+
ctx.Diags
156+
.diagnose(
157+
functionRepr->getStartLoc(),
158+
diag::attr_execution_nonisolated_behavior_will_change_typerepr,
159+
featureName, &attr)
160+
.fixItInsertAttribute(functionRepr->getStartLoc(), &attr);
161+
}
162+
}
163+
164+
void swift::warnAboutNewNonisolatedAsyncExecutionBehavior(
165+
ASTContext &ctx, FunctionTypeRepr *repr, FunctionTypeIsolation isolation) {
166+
AsyncCallerExecutionMigrationTarget(ctx, repr, isolation).diagnose();
167+
}
168+
169+
void swift::warnAboutNewNonisolatedAsyncExecutionBehavior(
170+
ASTContext &ctx, ValueDecl *decl, ActorIsolation isolation) {
171+
AsyncCallerExecutionMigrationTarget(ctx, decl, isolation).diagnose();
172+
}
173+
174+
void swift::warnAboutNewNonisolatedAsyncExecutionBehavior(
175+
ASTContext &ctx, AbstractClosureExpr *closure, ActorIsolation isolation) {
176+
AsyncCallerExecutionMigrationTarget(ctx, closure, isolation).diagnose();
177+
}
+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
//===-- Sema/AsyncCallerExecutionMigration.h --------------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2025 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
///
13+
/// \file
14+
/// This file provides code migration support for the `AsyncCallerExecution`
15+
/// feature.
16+
///
17+
//===----------------------------------------------------------------------===//
18+
19+
#ifndef SWIFT_SEMA_ASYNCCALLEREXECUTIONMIGRATION_H
20+
#define SWIFT_SEMA_ASYNCCALLEREXECUTIONMIGRATION_H
21+
22+
#include "swift/AST/ActorIsolation.h"
23+
#include "swift/AST/ExtInfo.h"
24+
25+
namespace swift {
26+
27+
class FunctionTypeRepr;
28+
class ValueDecl;
29+
class AbstractClosureExpr;
30+
31+
/// Warns that the behavior of nonisolated async functions will change under
32+
/// `AsyncCallerExecution` and suggests `@execution(concurrent)` to preserve
33+
/// the current behavior.
34+
void warnAboutNewNonisolatedAsyncExecutionBehavior(
35+
ASTContext &ctx, FunctionTypeRepr *node, FunctionTypeIsolation isolation);
36+
37+
/// Warns that the behavior of nonisolated async functions will change under
38+
/// `AsyncCallerExecution` and suggests `@execution(concurrent)` to preserve
39+
/// the current behavior.
40+
void warnAboutNewNonisolatedAsyncExecutionBehavior(ASTContext &ctx,
41+
ValueDecl *node,
42+
ActorIsolation isolation);
43+
44+
/// Warns that the behavior of nonisolated async functions will change under
45+
/// `AsyncCallerExecution` and suggests `@execution(concurrent)` to preserve
46+
/// the current behavior.
47+
void warnAboutNewNonisolatedAsyncExecutionBehavior(ASTContext &ctx,
48+
AbstractClosureExpr *node,
49+
ActorIsolation isolation);
50+
51+
} // end namespace swift
52+
53+
#endif /* SWIFT_SEMA_ASYNCCALLEREXECUTIONMIGRATION_H */

‎lib/Sema/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11

22
add_swift_host_library(swiftSema STATIC
33
AssociatedTypeInference.cpp
4+
AsyncCallerExecutionMigration.cpp
45
BuilderTransform.cpp
56
Comment.cpp
67
CSApply.cpp

0 commit comments

Comments
 (0)
Please sign in to comment.