Skip to content

Commit 2b5fa0e

Browse files
authored
Merge pull request #74705 from gottesmm/pr-93a2750af4fb0c65ca129d545c4af30cd9e718f9
[region-isolation] Given a .none #isolation parameter, infer the isolation from the callee rather than the isolated parameter.
2 parents 4b98498 + f43911b commit 2b5fa0e

File tree

3 files changed

+75
-19
lines changed

3 files changed

+75
-19
lines changed

lib/SILOptimizer/Analysis/RegionAnalysis.cpp

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1590,6 +1590,10 @@ class PartitionOpTranslator {
15901590
SmallVector<SILValue, 8> assignOperands;
15911591
SmallVector<SILValue, 8> assignResults;
15921592

1593+
// A helper we use to emit an unknown patten error if our merge is
1594+
// invalid. This ensures we guarantee that if we find an actor merge error,
1595+
// the compiler halts. Importantly this lets our users know 100% that if the
1596+
// compiler exits successfully, actor merge errors could not have happened.
15931597
std::optional<SILDynamicMergedIsolationInfo> mergedInfo;
15941598
if (resultIsolationInfoOverride) {
15951599
mergedInfo = resultIsolationInfoOverride;
@@ -1600,12 +1604,26 @@ class PartitionOpTranslator {
16001604
for (SILValue src : sourceValues) {
16011605
if (auto value = tryToTrackValue(src)) {
16021606
assignOperands.push_back(value->getRepresentative().getValue());
1603-
mergedInfo = mergedInfo->merge(value->getIsolationRegionInfo());
1607+
auto originalMergedInfo = mergedInfo;
1608+
(void)originalMergedInfo;
1609+
if (mergedInfo)
1610+
mergedInfo = mergedInfo->merge(value->getIsolationRegionInfo());
16041611

16051612
// If we fail to merge, then we have an incompatibility in between some
16061613
// of our arguments (consider isolated to different actors) or with the
16071614
// isolationInfo we specified. Emit an unknown patten error.
16081615
if (!mergedInfo) {
1616+
LLVM_DEBUG(
1617+
llvm::dbgs() << "Merge Failure!\n"
1618+
<< "Original Info: ";
1619+
if (originalMergedInfo)
1620+
originalMergedInfo->printForDiagnostics(llvm::dbgs());
1621+
else llvm::dbgs() << "nil";
1622+
llvm::dbgs() << "\nValue: "
1623+
<< value->getRepresentative().getValue();
1624+
llvm::dbgs() << "Value Info: ";
1625+
value->getIsolationRegionInfo().printForDiagnostics(llvm::dbgs());
1626+
llvm::dbgs() << "\n");
16091627
builder.addUnknownPatternError(src);
16101628
continue;
16111629
}
@@ -1614,7 +1632,7 @@ class PartitionOpTranslator {
16141632

16151633
for (SILValue result : resultValues) {
16161634
// If we had isolation info explicitly passed in... use our
1617-
// mergedInfo. Otherwise, we want to infer.
1635+
// resultIsolationInfoError. Otherwise, we want to infer.
16181636
if (resultIsolationInfoOverride) {
16191637
// We only get back result if it is non-Sendable.
16201638
if (auto nonSendableValue =
@@ -1657,9 +1675,10 @@ class PartitionOpTranslator {
16571675
// derived, introduce a fake element so we just propagate the actor
16581676
// region.
16591677
//
1660-
// NOTE: Here we check if we have mergedInfo rather than isolationInfo
1661-
// since we want to do this regardless of whether or not we passed in a
1662-
// specific isolation info unlike earlier when processing actual results.
1678+
// NOTE: Here we check if we have resultIsolationInfoOverride rather than
1679+
// isolationInfo since we want to do this regardless of whether or not we
1680+
// passed in a specific isolation info unlike earlier when processing
1681+
// actual results.
16631682
if (assignOperands.size() && resultIsolationInfoOverride) {
16641683
builder.addActorIntroducingInst(assignOperands.back(),
16651684
resultIsolationInfoOverride);

lib/SILOptimizer/Utils/SILIsolationInfo.cpp

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -364,21 +364,31 @@ SILIsolationInfo SILIsolationInfo::get(SILInstruction *inst) {
364364
}
365365

366366
if (auto *isolatedOp = fas.getIsolatedArgumentOperandOrNullPtr()) {
367-
// First pattern match from global actors being passed as isolated
368-
// parameters. This gives us better type information. If we can pattern
369-
// match... we should!
367+
// First see if we have an enum inst.
370368
if (auto *ei = dyn_cast<EnumInst>(isolatedOp->get())) {
371-
if (ei->getElement()->getParentEnum()->isOptionalDecl() &&
372-
ei->hasOperand()) {
373-
if (auto *ieri = dyn_cast<InitExistentialRefInst>(ei->getOperand())) {
374-
CanType selfASTType = ieri->getFormalConcreteType();
375-
376-
if (auto *nomDecl = selfASTType->getAnyActor()) {
377-
// The SILValue() parameter doesn't matter until we have isolation
378-
// history.
379-
if (nomDecl->isGlobalActor())
380-
return SILIsolationInfo::getGlobalActorIsolated(SILValue(),
381-
nomDecl);
369+
if (ei->getElement()->getParentEnum()->isOptionalDecl()) {
370+
// Pattern match from global actors being passed as isolated
371+
// parameters. This gives us better type information. If we can
372+
// pattern match... we should!
373+
if (ei->hasOperand()) {
374+
if (auto *ieri =
375+
dyn_cast<InitExistentialRefInst>(ei->getOperand())) {
376+
CanType selfASTType = ieri->getFormalConcreteType();
377+
378+
if (auto *nomDecl = selfASTType->getAnyActor()) {
379+
// The SILValue() parameter doesn't matter until we have
380+
// isolation history.
381+
if (nomDecl->isGlobalActor())
382+
return SILIsolationInfo::getGlobalActorIsolated(SILValue(),
383+
nomDecl);
384+
}
385+
}
386+
} else {
387+
// In this case, we have a .none so we are attempting to use the
388+
// global queue. In such a case, we need to not use the enum as our
389+
// value and instead need to grab the isolation of our apply.
390+
if (auto isolationInfo = get(fas.getCallee())) {
391+
return isolationInfo;
382392
}
383393
}
384394
}

test/Concurrency/transfernonsendable.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1767,3 +1767,30 @@ extension MyActor {
17671767
}
17681768
}
17691769
}
1770+
1771+
public struct TimeoutError: Error, CustomStringConvertible {
1772+
public var description: String { "Timed out" }
1773+
}
1774+
1775+
// We used to not merge the isolation below correctly causing us to emit a crash
1776+
// due to undefined behavior. Make sure we do not crash or emit an unhandled
1777+
// pattern error.
1778+
public func doNotCrashOrEmitUnhandledPatternErrors<T: Sendable>(
1779+
_ duration: Duration,
1780+
_ body: @escaping @Sendable () async throws -> T
1781+
) async throws -> T {
1782+
try await withThrowingTaskGroup(of: T.self) { taskGroup in
1783+
taskGroup.addTask {
1784+
try await Task.sleep(for: duration)
1785+
throw TimeoutError()
1786+
}
1787+
taskGroup.addTask {
1788+
return try await body()
1789+
}
1790+
for try await value in taskGroup {
1791+
taskGroup.cancelAll()
1792+
return value
1793+
}
1794+
throw CancellationError()
1795+
}
1796+
}

0 commit comments

Comments
 (0)