Skip to content

Commit dbc63eb

Browse files
committed
Synchronous closures can have global actors as part of their type
1 parent d6fc1fd commit dbc63eb

File tree

7 files changed

+63
-35
lines changed

7 files changed

+63
-35
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4502,9 +4502,6 @@ ERROR(global_actor_non_unsafe_init,none,
45024502
ERROR(actor_isolation_multiple_attr,none,
45034503
"%0 %1 has multiple actor-isolation attributes ('%2' and '%3')",
45044504
(DescriptiveDeclKind, DeclName, StringRef, StringRef))
4505-
ERROR(global_actor_isolated_synchronous_closure,none,
4506-
"closure isolated to global actor %0 must be 'async'",
4507-
(Type))
45084505
ERROR(actor_isolation_override_mismatch,none,
45094506
"%0 %1 %2 has different actor isolation from %3 overridden declaration",
45104507
(ActorIsolation, DescriptiveDeclKind, DeclName, ActorIsolation))

lib/Sema/CSGen.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
// This file implements constraint generation for the type checker.
1414
//
1515
//===----------------------------------------------------------------------===//
16+
#include "TypeCheckConcurrency.h"
1617
#include "TypeCheckType.h"
1718
#include "TypeChecker.h"
1819
#include "swift/AST/ASTVisitor.h"
@@ -2045,6 +2046,11 @@ namespace {
20452046
: TVO_CanBindToHole));
20462047
}();
20472048

2049+
// For a non-async function type, add the global actor if present.
2050+
if (!extInfo.isAsync()) {
2051+
extInfo = extInfo.withGlobalActor(getExplicitGlobalActor(closure));
2052+
}
2053+
20482054
return FunctionType::get(closureParams, resultTy, extInfo);
20492055
}
20502056

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,25 @@ GlobalActorAttributeRequest::evaluate(
551551
return result;
552552
}
553553

554+
Type swift::getExplicitGlobalActor(ClosureExpr *closure) {
555+
// Look at the explicit attribute.
556+
auto globalActorAttr = evaluateOrDefault(
557+
closure->getASTContext().evaluator,
558+
GlobalActorAttributeRequest{closure}, None);
559+
if (!globalActorAttr)
560+
return Type();
561+
562+
Type globalActor = evaluateOrDefault(
563+
closure->getASTContext().evaluator,
564+
CustomAttrTypeRequest{
565+
globalActorAttr->first, closure, CustomAttrTypeKind::GlobalActor},
566+
Type());
567+
if (!globalActor || globalActor->hasError())
568+
return Type();
569+
570+
return globalActor;
571+
}
572+
554573
/// Determine the isolation rules for a given declaration.
555574
ActorIsolationRestriction ActorIsolationRestriction::forDeclaration(
556575
ConcreteDeclRef declRef) {
@@ -2176,34 +2195,16 @@ namespace {
21762195

21772196
// Attempt to resolve the global actor type of a closure.
21782197
Type resolveGlobalActorType(ClosureExpr *closure) {
2179-
auto globalActorAttr = evaluateOrDefault(
2180-
ctx.evaluator, GlobalActorAttributeRequest{closure}, None);
2181-
if (!globalActorAttr)
2182-
return Type();
2183-
2184-
Type globalActor = evaluateOrDefault(
2185-
ctx.evaluator,
2186-
CustomAttrTypeRequest{
2187-
globalActorAttr->first, closure, CustomAttrTypeKind::GlobalActor},
2188-
Type());
2189-
if (!globalActor || globalActor->hasError())
2190-
return Type();
2191-
2192-
// Actor-isolated closures must be async.
2193-
bool isAsync = false;
2198+
// Check whether the closure's type has a global actor already.
21942199
if (Type closureType = closure->getType()) {
2195-
if (auto closureFnType = closureType->getAs<FunctionType>())
2196-
isAsync = closureFnType->isAsync();
2197-
}
2198-
2199-
if (!isAsync) {
2200-
ctx.Diags.diagnose(
2201-
closure->getLoc(), diag::global_actor_isolated_synchronous_closure,
2202-
globalActor);
2203-
return Type();
2200+
if (auto closureFnType = closureType->getAs<FunctionType>()) {
2201+
if (Type globalActor = closureFnType->getGlobalActor())
2202+
return globalActor;
2203+
}
22042204
}
22052205

2206-
return globalActor;
2206+
// Look for an explicit attribute.
2207+
return getExplicitGlobalActor(closure);
22072208
}
22082209

22092210
/// Determine the isolation of a particular closure.

lib/Sema/TypeCheckConcurrency.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class ActorIsolation;
2828
class AnyFunctionType;
2929
class ASTContext;
3030
class ClassDecl;
31+
class ClosureExpr;
3132
class ConcreteDeclRef;
3233
class CustomAttr;
3334
class Decl;
@@ -223,6 +224,9 @@ Optional<std::pair<CustomAttr *, NominalTypeDecl *>>
223224
checkGlobalActorAttributes(
224225
SourceLoc loc, DeclContext *dc, ArrayRef<CustomAttr *> attrs);
225226

227+
/// Get the explicit global actor specified for a closure.
228+
Type getExplicitGlobalActor(ClosureExpr *closure);
229+
226230
/// Check the correctness of the given ConcurrentValue conformance.
227231
///
228232
/// \returns true if an error occurred.

lib/Sema/TypeCheckType.cpp

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2100,12 +2100,7 @@ TypeResolver::resolveAttributedType(TypeAttributes &attrs, TypeRepr *repr,
21002100
attrs.getCustomAttrs().begin(), attrs.getCustomAttrs().end()));
21012101
if (foundGlobalActor) {
21022102
globalActorAttr = foundGlobalActor->first;
2103-
globalActor = evaluateOrDefault(
2104-
getASTContext().evaluator,
2105-
CustomAttrTypeRequest{
2106-
foundGlobalActor->first, getDeclContext(),
2107-
CustomAttrTypeKind::GlobalActor},
2108-
Type());
2103+
globalActor = resolveType(globalActorAttr->getTypeRepr(), options);
21092104
if (globalActor->hasError())
21102105
globalActor = Type();
21112106
}

test/Concurrency/actor_isolation.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ func testGlobalActorClosures() {
372372
return 17
373373
}
374374

375-
acceptConcurrentClosure { @SomeGlobalActor in 5 } // expected-error{{closure isolated to global actor 'SomeGlobalActor' must be 'async'}}
375+
acceptConcurrentClosure { @SomeGlobalActor in 5 } // expected-error{{converting function value of type '@SomeGlobalActor @concurrent () -> Int' to '@concurrent () -> Int' loses global actor 'SomeGlobalActor'}}
376376
}
377377

378378
extension MyActor {

test/Concurrency/global_actor_function_types.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,28 @@ func testConversions(f: @escaping @SomeGlobalActor (Int) -> Void, g: @escaping (
2222
// FIXME: this could be better.
2323
let _: @OtherGlobalActor (Int) -> Void = f // expected-error{{cannot convert value of type 'SomeGlobalActor' to specified type 'OtherGlobalActor'}}
2424
}
25+
26+
@SomeGlobalActor func onSomeGlobalActor() -> Int { 5 }
27+
28+
func someSlowOperation() async -> Int { 5 }
29+
30+
func acceptOnSomeGlobalActor<T>(_: @SomeGlobalActor () -> T) { }
31+
32+
func testClosures() {
33+
// Global actors on synchronous closures become part of the type
34+
let cl1 = { @SomeGlobalActor in
35+
onSomeGlobalActor()
36+
}
37+
let _: Double = cl1 // expected-error{{cannot convert value of type '@SomeGlobalActor () -> Int' to specified type 'Double'}}
38+
39+
// Global actors on async closures do not become part of the type
40+
let cl2 = { @SomeGlobalActor in
41+
await someSlowOperation()
42+
}
43+
let _: Double = cl2 // expected-error{{cannot convert value of type '() async -> Int' to specified type 'Double'}}
44+
45+
// okay to be explicit
46+
acceptOnSomeGlobalActor { @SomeGlobalActor in
47+
onSomeGlobalActor()
48+
}
49+
}

0 commit comments

Comments
 (0)