[nonisolated-nonsending] Make the AST not consider nonisolated(nonsending) to be an actor isolation crossing point.

We were effectively working around this previously at the SIL level. This caused
us not to obey the semantics of the actual evolution proposal. As an example of
this, in the following, x should not be considered main actor isolated:

```swift
nonisolated(nonsending) func useValue<T>(_ t: T) async {}
@MainActor func test() async {
  let x = NS()
  await useValue(x)
  print(x)
}
```

we should just consider this to be a merge and since useValue does not have any
MainActor isolated parameters, x should not be main actor isolated and we should
not emit an error here.

I also fixed a separate issue where we were allowing for parameters of
nonisolated(nonsending) functions to be passed to @concurrent functions. We
cannot allow for this to happen since the nonisolated(nonsending) parameters
/could/ be actor isolated. Of course, we have lost that static information at
this point so we cannot allow for it. Given that we have the actual dynamic
actor isolation information, we could dynamically allow for the parameters to be
passed... but that is something that is speculative and is definitely outside of
the scope of this patch.

rdar://154139237
This commit is contained in:
Michael Gottesman
2025-06-25 13:57:48 -07:00
parent ce7a3b39a4
commit c12c99fb73
5 changed files with 283 additions and 31 deletions

View File

@@ -442,6 +442,21 @@ SILIsolationInfo SILIsolationInfo::get(SILInstruction *inst) {
return info;
}
// See if our function apply site has an implicit isolated parameter. In
// such a case, we know that we have a caller inheriting isolated
// function. Return that this has disconnected isolation.
//
// DISCUSSION: The reason why we are doing this is that we already know that
// the AST is not going to label this as an isolation crossing point so we
// will only perform a merge. We want to just perform an isolation merge
// without adding additional isolation info. Otherwise, a nonisolated
// function that
if (auto paramInfo = fas.getSubstCalleeType()->maybeGetIsolatedParameter();
paramInfo && paramInfo->hasOption(SILParameterInfo::ImplicitLeading) &&
paramInfo->hasOption(SILParameterInfo::Isolated)) {
return SILIsolationInfo::getDisconnected(false /*unsafe nonisolated*/);
}
if (auto *isolatedOp = fas.getIsolatedArgumentOperandOrNullPtr()) {
// First look through ActorInstance agnostic values so we can find the
// type of the actual underlying actor (e.x.: copy_value,
@@ -534,9 +549,8 @@ SILIsolationInfo SILIsolationInfo::get(SILInstruction *inst) {
if (actorInstance) {
if (auto actualIsolatedValue =
ActorInstance::getForValue(actorInstance)) {
// See if we have a function parameter. In that case, we want to see
// if we have a function argument. In such a case, we need to use
// the right parameter and the var decl.
// See if we have a function parameter. In such a case, we need to
// use the right parameter and the var decl.
if (auto *fArg = dyn_cast<SILFunctionArgument>(
actualIsolatedValue.getValue())) {
if (auto info =
@@ -980,6 +994,13 @@ SILIsolationInfo SILIsolationInfo::get(SILArgument *arg) {
// handles isolated self and specifically marked isolated.
if (auto *isolatedArg = llvm::cast_or_null<SILFunctionArgument>(
fArg->getFunction()->maybeGetIsolatedArgument())) {
// See if the function is nonisolated(nonsending). In such a case, return
// task isolated.
if (auto funcIsolation = fArg->getFunction()->getActorIsolation();
funcIsolation && funcIsolation->isCallerIsolationInheriting()) {
return SILIsolationInfo::getTaskIsolated(fArg);
}
auto astType = isolatedArg->getType().getASTType();
if (astType->lookThroughAllOptionalTypes()->getAnyActor()) {
return SILIsolationInfo::getActorInstanceIsolated(fArg, isolatedArg);