Skip to content

Commit 16af507

Browse files
committed
[Concurrency] tighten-up rules about isolated generic parameters
We were missing a check for conformance to `Actor` or `DistributedActor` when an isolated parameter's type is a generic parameter. Previously, if you used a generic parameter constrained to just `AnyActor`, you'd crash the compiler in LowerHopToExecutor because it doesn't know how to obtain the executor for such a value. Since `AnyActor` has no `unownedExecutor` requirement, there's no way to get the executor without emitting code to do dynamic casts down to `Actor` or `DistributedActor`. Rather than have the compiler silently emit dynamic casting, I figured it's best to ban it. This forces people to either do the dynamic casts themselves, or use one of the more specific types to constrain their parameter. For other generic parameters, we would silently treat the function as though it is nonisolated (i.e., as if the `isolated` wasn't written on the parameter at all). resolves rdar://109059544
1 parent 469a614 commit 16af507

File tree

4 files changed

+31
-3
lines changed

4 files changed

+31
-3
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5331,6 +5331,9 @@ NOTE(protocol_isolated_to_global_actor_here,none,
53315331

53325332
ERROR(isolated_parameter_not_actor,none,
53335333
"'isolated' parameter has non-actor type %0", (Type))
5334+
ERROR(isolated_parameter_no_actor_conformance,none,
5335+
"'isolated' parameter %0 must conform to 'Actor' "
5336+
"or 'DistributedActor' protocol", (Type))
53345337
ERROR(isolated_parameter_duplicate,none,
53355338
"cannot have more than one 'isolated' parameter", ())
53365339
ERROR(isolated_parameter_duplicate_type,none,

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4092,12 +4092,26 @@ ActorIsolation ActorIsolationRequest::evaluate(
40924092
if (auto paramIdx = getIsolatedParamIndex(value)) {
40934093
checkDeclWithIsolatedParameter(value);
40944094

4095-
// FIXME: This doesn't allow us to find an Actor or DistributedActor
4096-
// bound on the parameter type effectively.
4097-
auto param = getParameterList(value)->get(*paramIdx);
4095+
ParamDecl *param = getParameterList(value)->get(*paramIdx);
40984096
Type paramType = param->getInterfaceType();
40994097
if (paramType->isTypeParameter()) {
41004098
paramType = param->getDeclContext()->mapTypeIntoContext(paramType);
4099+
4100+
auto &ctx = value->getASTContext();
4101+
auto conformsTo = [&](KnownProtocolKind kind) {
4102+
if (auto *proto = ctx.getProtocol(kind))
4103+
return value->getModuleContext()->conformsToProtocol(paramType, proto);
4104+
return ProtocolConformanceRef::forInvalid();
4105+
};
4106+
4107+
// The type parameter must be bound by Actor or DistributedActor, as they
4108+
// have an unownedExecutor. AnyActor does NOT have an unownedExecutor!
4109+
if (!conformsTo(KnownProtocolKind::Actor)
4110+
&& !conformsTo(KnownProtocolKind::DistributedActor)) {
4111+
ctx.Diags.diagnose(param->getLoc(),
4112+
diag::isolated_parameter_no_actor_conformance,
4113+
paramType);
4114+
}
41014115
}
41024116

41034117
if (auto actor = paramType->getAnyActor())

test/Concurrency/isolated_parameters.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,3 +348,12 @@ func getValues(
348348
actor.dictionary[key]
349349
}
350350
}
351+
352+
func isolated_generic_bad_1<T>(_ t: isolated T) {}
353+
// expected-error@-1 {{'isolated' parameter 'T' must conform to 'Actor' or 'DistributedActor' protocol}}
354+
func isolated_generic_bad_2<T: Equatable>(_ t: isolated T) {}
355+
// expected-error@-1 {{'isolated' parameter 'T' must conform to 'Actor' or 'DistributedActor' protocol}}
356+
func isolated_generic_bad_3<T: AnyActor>(_ t: isolated T) {}
357+
// expected-error@-1 {{'isolated' parameter 'T' must conform to 'Actor' or 'DistributedActor' protocol}}
358+
359+
func isolated_generic_ok_1<T: Actor>(_ t: isolated T) {}

test/Distributed/distributed_actor_isolation.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,3 +258,5 @@ extension Greeting where SerializationRequirement == Codable {
258258
try await greetLocal(name: "Alice") // expected-error{{only 'distributed' instance methods can be called on a potentially remote distributed actor}}
259259
}
260260
}
261+
262+
func isolated_generic_ok<T: DistributedActor>(_ t: isolated T) {}

0 commit comments

Comments
 (0)