Skip to content

Commit 1c546e9

Browse files
authored
Merge pull request #82857 from xedin/inheritActorContext-and-nonisolated-nonsending
[Concurrency] Prevent use of `nonisolated(nonsending)` and `@concurrent`
2 parents e9a35c0 + e42ac61 commit 1c546e9

File tree

9 files changed

+73
-12
lines changed

9 files changed

+73
-12
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8706,6 +8706,14 @@ ERROR(inherit_actor_context_only_on_async_or_isolation_erased_params,none,
87068706
"asynchronous function types",
87078707
(DeclAttribute))
87088708

8709+
ERROR(inherit_actor_context_with_concurrent,none,
8710+
"'@_inheritActorContext' attribute cannot be used together with %0",
8711+
(const TypeAttribute *))
8712+
8713+
ERROR(inherit_actor_context_with_nonisolated_nonsending,none,
8714+
"'@_inheritActorContext' attribute cannot be used together with %0",
8715+
(TypeRepr *))
8716+
87098717
//===----------------------------------------------------------------------===//
87108718
// MARK: @concurrent and nonisolated(nonsending) attributes
87118719
//===----------------------------------------------------------------------===//

lib/Sema/TypeCheckAttr.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7871,6 +7871,9 @@ void AttributeChecker::visitInheritActorContextAttr(
78717871
return;
78727872

78737873
auto paramTy = P->getInterfaceType();
7874+
if (paramTy->hasError())
7875+
return;
7876+
78747877
auto *funcTy =
78757878
paramTy->lookThroughAllOptionalTypes()->getAs<AnyFunctionType>();
78767879
if (!funcTy) {

lib/Sema/TypeCheckDecl.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2337,6 +2337,9 @@ static Type validateParameterType(ParamDecl *decl) {
23372337
if (dc->isInSpecializeExtensionContext())
23382338
options |= TypeResolutionFlags::AllowUsableFromInline;
23392339

2340+
if (decl->getAttrs().hasAttribute<InheritActorContextAttr>())
2341+
options |= TypeResolutionFlags::InheritsActorContext;
2342+
23402343
Type Ty;
23412344

23422345
auto *nestedRepr = decl->getTypeRepr();

lib/Sema/TypeCheckType.cpp

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4219,6 +4219,11 @@ NeverNullType TypeResolver::resolveASTFunctionType(
42194219
attr->getAttrName());
42204220
}
42214221

4222+
if (options.contains(TypeResolutionFlags::InheritsActorContext)) {
4223+
diagnoseInvalid(repr, attr->getAttrLoc(),
4224+
diag::inherit_actor_context_with_concurrent, attr);
4225+
}
4226+
42224227
switch (isolation.getKind()) {
42234228
case FunctionTypeIsolation::Kind::NonIsolated:
42244229
break;
@@ -4265,18 +4270,20 @@ NeverNullType TypeResolver::resolveASTFunctionType(
42654270
if (!repr->isInvalid())
42664271
isolation = FunctionTypeIsolation::forNonIsolated();
42674272
} else if (!getWithoutClaiming<CallerIsolatedTypeRepr>(attrs)) {
4268-
// Infer async function type as `nonisolated(nonsending)` if there is
4269-
// no `@concurrent` or `nonisolated(nonsending)` attribute and isolation
4270-
// is nonisolated.
4271-
if (ctx.LangOpts.hasFeature(Feature::NonisolatedNonsendingByDefault) &&
4272-
repr->isAsync() && isolation.isNonIsolated()) {
4273-
isolation = FunctionTypeIsolation::forNonIsolatedCaller();
4274-
} else if (ctx.LangOpts
4275-
.getFeatureState(Feature::NonisolatedNonsendingByDefault)
4276-
.isEnabledForMigration()) {
4277-
// Diagnose only in the interface stage, which is run once.
4278-
if (inStage(TypeResolutionStage::Interface)) {
4279-
warnAboutNewNonisolatedAsyncExecutionBehavior(ctx, repr, isolation);
4273+
if (!options.contains(TypeResolutionFlags::InheritsActorContext)) {
4274+
// Infer async function type as `nonisolated(nonsending)` if there is
4275+
// no `@concurrent` or `nonisolated(nonsending)` attribute and isolation
4276+
// is nonisolated.
4277+
if (ctx.LangOpts.hasFeature(Feature::NonisolatedNonsendingByDefault) &&
4278+
repr->isAsync() && isolation.isNonIsolated()) {
4279+
isolation = FunctionTypeIsolation::forNonIsolatedCaller();
4280+
} else if (ctx.LangOpts
4281+
.getFeatureState(Feature::NonisolatedNonsendingByDefault)
4282+
.isEnabledForMigration()) {
4283+
// Diagnose only in the interface stage, which is run once.
4284+
if (inStage(TypeResolutionStage::Interface)) {
4285+
warnAboutNewNonisolatedAsyncExecutionBehavior(ctx, repr, isolation);
4286+
}
42804287
}
42814288
}
42824289
}
@@ -5326,6 +5333,12 @@ TypeResolver::resolveCallerIsolatedTypeRepr(CallerIsolatedTypeRepr *repr,
53265333
return ErrorType::get(getASTContext());
53275334
}
53285335

5336+
if (options.contains(TypeResolutionFlags::InheritsActorContext)) {
5337+
diagnoseInvalid(repr, repr->getLoc(),
5338+
diag::inherit_actor_context_with_nonisolated_nonsending,
5339+
repr);
5340+
}
5341+
53295342
if (!fnType->isAsync()) {
53305343
diagnoseInvalid(repr, repr->getStartLoc(),
53315344
diag::nonisolated_nonsending_only_on_async, repr);

lib/Sema/TypeCheckType.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ enum class TypeResolutionFlags : uint16_t {
8787

8888
/// Whether the immediate context has an @escaping attribute.
8989
DirectEscaping = 1 << 14,
90+
91+
/// We are in a `@_inheritActorContext` parameter declaration.
92+
InheritsActorContext = 1 << 15,
9093
};
9194

9295
/// Type resolution contexts that require special handling.

test/Concurrency/attr_execution/attr_execution.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,3 +80,16 @@ func testClosure() {
8080
takesClosure {
8181
}
8282
}
83+
84+
// CHECK-LABEL: // testInheritsActor(fn:)
85+
// CHECK: Isolation: global_actor. type: MainActor
86+
// CHECK: sil hidden [ossa] @$s14attr_execution17testInheritsActor2fnyyyYaYbXE_tYaF : $@convention(thin) @async (@guaranteed @noescape @Sendable @async @callee_guaranteed () -> ()) -> ()
87+
// CHECK: bb0([[FN:%.*]] : @guaranteed $@noescape @Sendable @async @callee_guaranteed () -> ()):
88+
// CHECK: [[FN_COPY:%.*]] = copy_value [[FN]]
89+
// CHECK: [[BORROWED_FN_COPY:%.*]] = begin_borrow [[FN_COPY]]
90+
// CHECK: apply [[BORROWED_FN_COPY]]() : $@noescape @Sendable @async @callee_guaranteed () -> ()
91+
// CHECK: } // end sil function '$s14attr_execution17testInheritsActor2fnyyyYaYbXE_tYaF'
92+
@MainActor
93+
func testInheritsActor(@_inheritActorContext(always) fn: @Sendable () async -> Void) async {
94+
await fn()
95+
}

test/Concurrency/attr_execution/migration_mode.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,3 +393,9 @@ do {
393393
}
394394
}
395395
}
396+
397+
// @_inheritActorContext prevents `nonisolated(nonsending)` inference.
398+
do {
399+
func testInherit1(@_inheritActorContext _: @Sendable () async -> Void) {}
400+
func testInherit2(@_inheritActorContext(always) _: (@Sendable () async -> Void)?) {}
401+
}

test/Concurrency/attr_execution/nonisolated_nonsending_by_default.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,8 @@ func testCasts() {
88
// expected-error@-1 {{cannot convert value of type '(nonisolated(nonsending) () async -> ()).Type' to type '(() async -> ()).Type' in coercion}}
99
_ = defaultedType as (nonisolated(nonsending) () async -> ()).Type // Ok
1010
}
11+
12+
func test(@_inheritActorContext fn: @Sendable () async -> Void) {
13+
let _: Int = fn
14+
// expected-error@-1 {{cannot convert value of type '@Sendable () async -> Void' to specified type 'Int'}}
15+
}

test/Parse/execution_behavior_attrs.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,10 @@ do {
8484
nonisolated(0) // expected-warning {{result of call to 'nonisolated' is unused}}
8585
print("hello")
8686
}
87+
88+
do {
89+
func testActorInheriting1(@_inheritActorContext _: @concurrent @Sendable () async -> Void) {}
90+
// expected-error@-1 {{'@_inheritActorContext' attribute cannot be used together with '@concurrent'}}
91+
func testActorInheriting2(@_inheritActorContext _: nonisolated(nonsending) @Sendable () async -> Void) {}
92+
// expected-error@-1 {{'@_inheritActorContext' attribute cannot be used together with 'nonisolated(nonsending)'}}
93+
}

0 commit comments

Comments
 (0)