Propagate global actor-ness of functions/closures.

I fixed a bunch of small issues around here that resulted in a bunch of radars
being fixed. Specifically:

1. I made it so that we treat function_refs that are from an actor isolated
function as actor isolated instead of sendable.

2. I made it so that autoclosures which return global actor isolated functions
are treated as producing a global actor isolated function.

3. I made it so that we properly handle SILGen code patterns produced by
Sendable GlobalActor isolated things.

rdar://125452372
rdar://121954871
rdar://121955895
rdar://122692698
This commit is contained in:
Michael Gottesman
2024-03-27 15:57:56 -07:00
parent 77dccacbd3
commit 1cf4e99454
9 changed files with 363 additions and 16 deletions

View File

@@ -1848,7 +1848,7 @@ public:
}
// If our self parameter was transferring, transfer it. Otherwise, just
// stick it in the non seld operand values array and run multiassign on
// stick it in the non self operand values array and run multiassign on
// it.
if (fas.hasSelfArgument()) {
auto &selfOperand = fas.getSelfArgumentOperand();
@@ -1864,6 +1864,12 @@ public:
}
}
// Add our callee to non-transferring parameters. This ensures that if it is
// actor isolated, that propagates into our results. This is especially
// important since our callee could be dynamically isolated and we cannot
// know that until we perform dataflow.
nonTransferringParameters.push_back(fas.getCallee());
SmallVector<SILValue, 8> applyResults;
getApplyResults(*fas, applyResults);
@@ -3283,12 +3289,59 @@ TrackableValue RegionAnalysisValueMap::getTrackableValue(
}
}
// Then see if we have a sendable value. By default we assume values are not
// sendable.
if (auto *defInst = value.getDefiningInstruction()) {
// Though these values are technically non-Sendable, we can safely and
// consistently treat them as Sendable.
if (isa<ClassMethodInst, FunctionRefInst>(defInst)) {
// Treat function ref as either actor isolated or sendable.
if (auto *fri = dyn_cast<FunctionRefInst>(defInst)) {
auto isolation = fri->getReferencedFunction()->getActorIsolation();
if (isolation.isActorIsolated()) {
iter.first->getSecond().mergeIsolationRegionInfo(
SILIsolationInfo::getActorIsolated(isolation));
return {iter.first->first, iter.first->second};
}
// Otherwise, lets look at the AST and see if our function ref is from an
// autoclosure.
if (auto *autoclosure = fri->getLoc().getAsASTNode<AutoClosureExpr>()) {
if (auto *funcType = autoclosure->getType()->getAs<AnyFunctionType>()) {
if (funcType->hasGlobalActor()) {
if (funcType->hasGlobalActor()) {
iter.first->getSecond().mergeIsolationRegionInfo(
SILIsolationInfo::getActorIsolated(
ActorIsolation::forGlobalActor(
funcType->getGlobalActor())));
return {iter.first->first, iter.first->second};
}
}
if (auto *resultFType =
funcType->getResult()->getAs<AnyFunctionType>()) {
if (resultFType->hasGlobalActor()) {
iter.first->getSecond().mergeIsolationRegionInfo(
SILIsolationInfo::getActorIsolated(
ActorIsolation::forGlobalActor(
resultFType->getGlobalActor())));
return {iter.first->first, iter.first->second};
}
}
}
}
iter.first->getSecond().addFlag(TrackableValueFlag::isSendable);
return {iter.first->first, iter.first->second};
}
if (auto *cmi = dyn_cast<ClassMethodInst>(defInst)) {
if (auto *declRefExpr = cmi->getLoc().getAsASTNode<DeclRefExpr>()) {
// See if we are actor isolated. If so, treat this as non-Sendable so we
// propagate actor isolation.
if (auto isolation = getActorIsolation(declRefExpr->getDecl())) {
if (isolation.isActorIsolated()) {
iter.first->getSecond().mergeIsolationRegionInfo(
SILIsolationInfo::getActorIsolated(isolation));
return {iter.first->first, iter.first->second};
}
}
}
iter.first->getSecond().addFlag(TrackableValueFlag::isSendable);
return {iter.first->first, iter.first->second};
}
@@ -3379,6 +3432,71 @@ TrackableValue RegionAnalysisValueMap::getTrackableValue(
}
}
// See if we have a convert function from a Sendable actor isolated function,
// we want to treat the result of the convert function as being actor isolated
// so that we cannot escape the value.
//
// NOTE: At this point, we already know that cfi's result is not sendable,
// since we would have exited above already.
if (auto *cfi = dyn_cast<ConvertFunctionInst>(iter.first->first.getValue())) {
SILValue operand = cfi->getOperand();
if (operand->getType().getAs<SILFunctionType>()->isSendable()) {
SILValue newValue = operand;
do {
operand = newValue;
newValue = lookThroughOwnershipInsts(operand);
if (auto *ttfi = dyn_cast<ThinToThickFunctionInst>(newValue)) {
newValue = ttfi->getOperand();
}
if (auto *cfi = dyn_cast<ConvertFunctionInst>(newValue)) {
newValue = cfi->getOperand();
}
if (auto *pai = dyn_cast<PartialApplyInst>(newValue)) {
newValue = pai->getCallee();
}
} while (newValue != operand);
if (auto *ai = dyn_cast<ApplyInst>(operand)) {
if (auto *callExpr = ai->getLoc().getAsASTNode<ApplyExpr>()) {
if (auto *callType = callExpr->getType()->getAs<AnyFunctionType>()) {
if (callType->hasGlobalActor()) {
iter.first->getSecond().mergeIsolationRegionInfo(
SILIsolationInfo::getGlobalActorIsolated(
callType->getGlobalActor()));
return {iter.first->first, iter.first->second};
}
}
}
}
if (auto *fri = dyn_cast<FunctionRefInst>(operand)) {
if (auto actorIsolation =
fri->getReferencedFunction()->getActorIsolation()) {
if (actorIsolation.isActorIsolated()) {
iter.first->getSecond().mergeIsolationRegionInfo(
SILIsolationInfo::getActorIsolated(actorIsolation));
return {iter.first->first, iter.first->second};
}
}
// See if the function ref statically is known to have actor isolation.
//
// TODO: We should make it so that the closure constructed has actor
// isolation.
if (auto value = tryToTrackValue(fri)) {
auto isolation = value->getIsolationRegionInfo();
if (isolation.isActorIsolated()) {
iter.first->getSecond().mergeIsolationRegionInfo(isolation);
return {iter.first->first, iter.first->second};
}
}
}
}
}
return {iter.first->first, iter.first->second};
}