Skip to content

Commit f43911b

Browse files
committed
[region-isolation] Given a .none #isolation parameter, infer the isolation from the callee rather than the isolated parameter.
Otherwise, we will have differing isolation from other parameters since the isolations will look different since one will have the .none value as an instance and the other will not have one and instead will rely on the AST isolation info. That is the correct behavior here since we do not actually have an actor here. I also removed some undefined behavior in the merging code. The way the code should work is that we should check if the merge fails and in such a case emit an unknown pattern error... instead of not checking appropriately on the next iteration and hitting undefined behavior. rdar://130396399
1 parent 11696cd commit f43911b

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)