Skip to content

Commit aff9248

Browse files
committed
[CSApply] Use ActorIsolationErasure conversion in argument positions that require runtime check
Passing an isolated function value into an API that doesn't have full static concurrency checking is unsafe and requires runtime checks to make sure that function is always called in the expected context.
1 parent 2e9fffb commit aff9248

File tree

1 file changed

+48
-0
lines changed

1 file changed

+48
-0
lines changed

lib/Sema/CSApply.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7416,6 +7416,54 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
74167416
}
74177417
}
74187418

7419+
if (ctx.LangOpts.hasFeature(Feature::PreconcurrencyConformances)) {
7420+
// Passing a synchronous global actor-isolated function value and
7421+
// parameter that expects a synchronous non-isolated function type could
7422+
// require a runtime check to ensure that function is always called in
7423+
// expected context.
7424+
if (!toEI.getGlobalActor() && fromEI.getGlobalActor() &&
7425+
!toEI.isAsync()) {
7426+
// Runtime check is required when isolation function value
7427+
// is passed to an API that comes from a module that doesn't
7428+
// have full static concurrency checking enabled.
7429+
auto requiresRuntimeCheck = [&]() {
7430+
if (!locator.endsWith<LocatorPathElt::ApplyArgToParam>())
7431+
return false;
7432+
7433+
ConstraintLocator *calleeLoc = nullptr;
7434+
if (auto *call = getAsExpr<ApplyExpr>(locator.getAnchor())) {
7435+
calleeLoc = CalleeLocators[call];
7436+
} else {
7437+
calleeLoc =
7438+
solution.getCalleeLocator(cs.getConstraintLocator(locator));
7439+
}
7440+
7441+
auto overload = solution.getOverloadChoiceIfAvailable(calleeLoc);
7442+
if (!(overload && overload->choice.isDecl()))
7443+
return false;
7444+
7445+
auto *overloadModule = overload->choice.getDecl()->getModuleContext();
7446+
return overloadModule != dc->getParentModule() &&
7447+
!overloadModule->getLanguageVersionBuiltWith()
7448+
.isVersionAtLeast(6);
7449+
};
7450+
7451+
if (requiresRuntimeCheck()) {
7452+
auto isolatedToType =
7453+
FunctionType::get(toFunc->getParams(), toFunc->getResult(),
7454+
toEI.withGlobalActor(fromEI.getGlobalActor()));
7455+
7456+
// Global actor might not be the only difference, let's introduce
7457+
// a function conversion first but with matching isolation.
7458+
expr = cs.cacheType(new (ctx)
7459+
FunctionConversionExpr(expr, isolatedToType));
7460+
7461+
return cs.cacheType(new (ctx)
7462+
ActorIsolationErasureExpr(expr, toType));
7463+
}
7464+
}
7465+
}
7466+
74197467
maybeDiagnoseUnsupportedFunctionConversion(cs, expr, toFunc);
74207468

74217469
return cs.cacheType(new (ctx) FunctionConversionExpr(expr, toType));

0 commit comments

Comments
 (0)