mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[TypeChecker] Allow closures to assume nonisolated(nonsending)
Always infer `nonisolated(nonsending)` from context directly on
a closure unless the closure is marked as `@concurrent`, otherwise
the closure is not going to get correct isolation and going to hop
to the wrong executor in its preamble.
Resolves: rdar://149107104
(cherry picked from commit 3de72c5452)
This commit is contained in:
@@ -6494,18 +6494,31 @@ ArgumentList *ExprRewriter::coerceCallArguments(
|
||||
return ArgumentList::createTypeChecked(ctx, args, newArgs);
|
||||
}
|
||||
|
||||
/// Looks through any non-semantic expressions and a capture list
|
||||
/// to find out whether the given expression is an explicit closure.
|
||||
static ClosureExpr *isExplicitClosureExpr(Expr *expr) {
|
||||
if (auto IE = dyn_cast<IdentityExpr>(expr))
|
||||
return isExplicitClosureExpr(IE->getSubExpr());
|
||||
|
||||
if (auto CLE = dyn_cast<CaptureListExpr>(expr))
|
||||
return isExplicitClosureExpr(CLE->getClosureBody());
|
||||
|
||||
return dyn_cast<ClosureExpr>(expr);
|
||||
}
|
||||
|
||||
/// Whether the given expression is a closure that should inherit
|
||||
/// the actor context from where it was formed.
|
||||
static bool closureInheritsActorContext(Expr *expr) {
|
||||
if (auto IE = dyn_cast<IdentityExpr>(expr))
|
||||
return closureInheritsActorContext(IE->getSubExpr());
|
||||
|
||||
if (auto CLE = dyn_cast<CaptureListExpr>(expr))
|
||||
return closureInheritsActorContext(CLE->getClosureBody());
|
||||
|
||||
if (auto CE = dyn_cast<ClosureExpr>(expr))
|
||||
if (auto *CE = isExplicitClosureExpr(expr))
|
||||
return CE->inheritsActorContext();
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Determine whether the given expression is a closure that
|
||||
/// is explicitly marked as `@concurrent`.
|
||||
static bool isClosureMarkedAsConcurrent(Expr *expr) {
|
||||
if (auto *CE = isExplicitClosureExpr(expr))
|
||||
return CE->getAttrs().hasAttribute<ConcurrentAttr>();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -7747,6 +7760,23 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
|
||||
}
|
||||
}
|
||||
|
||||
// If we have a ClosureExpr, then we can safely propagate the
|
||||
// 'nonisolated(nonsending)' isolation if it's not explicitly
|
||||
// marked as `@concurrent`.
|
||||
if (toEI.getIsolation().isNonIsolatedCaller() &&
|
||||
(fromEI.getIsolation().isNonIsolated() &&
|
||||
!isClosureMarkedAsConcurrent(expr))) {
|
||||
auto newFromFuncType = fromFunc->withIsolation(
|
||||
FunctionTypeIsolation::forNonIsolatedCaller());
|
||||
if (applyTypeToClosureExpr(cs, expr, newFromFuncType)) {
|
||||
fromFunc = newFromFuncType->castTo<FunctionType>();
|
||||
// Propagating 'nonisolated(nonsending)' might have satisfied the entire
|
||||
// conversion. If so, we're done, otherwise keep converting.
|
||||
if (fromFunc->isEqual(toType))
|
||||
return expr;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx.LangOpts.isDynamicActorIsolationCheckingEnabled()) {
|
||||
// Passing a synchronous global actor-isolated function value and
|
||||
// parameter that expects a synchronous non-isolated function type could
|
||||
|
||||
Reference in New Issue
Block a user