Skip to content

Commit ebc8afc

Browse files
authored
Merge pull request #74727 from gottesmm/release/6.0-rdar130396399
[6.0][region-isolation] Given a .none #isolation parameter, infer the isolation from the callee rather than the isolated parameter.
2 parents 2e89580 + 61e0096 commit ebc8afc

File tree

3 files changed

+74
-19
lines changed

3 files changed

+74
-19
lines changed

lib/SILOptimizer/Analysis/RegionAnalysis.cpp

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

1591+
// A helper we use to emit an unknown patten error if our merge is
1592+
// invalid. This ensures we guarantee that if we find an actor merge error,
1593+
// the compiler halts. Importantly this lets our users know 100% that if the
1594+
// compiler exits successfully, actor merge errors could not have happened.
15911595
std::optional<SILDynamicMergedIsolationInfo> mergedInfo;
15921596
if (resultIsolationInfoOverride) {
15931597
mergedInfo = resultIsolationInfoOverride;
@@ -1598,12 +1602,26 @@ class PartitionOpTranslator {
15981602
for (SILValue src : sourceValues) {
15991603
if (auto value = tryToTrackValue(src)) {
16001604
assignOperands.push_back(value->getRepresentative().getValue());
1601-
mergedInfo = mergedInfo->merge(value->getIsolationRegionInfo());
1605+
auto originalMergedInfo = mergedInfo;
1606+
(void)originalMergedInfo;
1607+
if (mergedInfo)
1608+
mergedInfo = mergedInfo->merge(value->getIsolationRegionInfo());
16021609

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

16131631
for (SILValue result : resultValues) {
16141632
// If we had isolation info explicitly passed in... use our
1615-
// mergedInfo. Otherwise, we want to infer.
1633+
// resultIsolationInfoError. Otherwise, we want to infer.
16161634
if (resultIsolationInfoOverride) {
16171635
// We only get back result if it is non-Sendable.
16181636
if (auto nonSendableValue =
@@ -1647,9 +1665,10 @@ class PartitionOpTranslator {
16471665
// derived, introduce a fake element so we just propagate the actor
16481666
// region.
16491667
//
1650-
// NOTE: Here we check if we have mergedInfo rather than isolationInfo
1651-
// since we want to do this regardless of whether or not we passed in a
1652-
// specific isolation info unlike earlier when processing actual results.
1668+
// NOTE: Here we check if we have resultIsolationInfoOverride rather than
1669+
// isolationInfo since we want to do this regardless of whether or not we
1670+
// passed in a specific isolation info unlike earlier when processing
1671+
// actual results.
16531672
if (assignOperands.size() && resultIsolationInfoOverride) {
16541673
builder.addActorIntroducingInst(assignOperands.back(),
16551674
resultIsolationInfoOverride);

lib/SILOptimizer/Utils/SILIsolationInfo.cpp

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

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

test/Concurrency/transfernonsendable.swift

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1758,3 +1758,29 @@ extension MyActor {
17581758
}
17591759
}
17601760

1761+
public struct TimeoutError: Error, CustomStringConvertible {
1762+
public var description: String { "Timed out" }
1763+
}
1764+
1765+
// We used to not merge the isolation below correctly causing us to emit a crash
1766+
// due to undefined behavior. Make sure we do not crash or emit an unhandled
1767+
// pattern error.
1768+
public func doNotCrashOrEmitUnhandledPatternErrors<T: Sendable>(
1769+
_ duration: Duration,
1770+
_ body: @escaping @Sendable () async throws -> T
1771+
) async throws -> T {
1772+
try await withThrowingTaskGroup(of: T.self) { taskGroup in
1773+
taskGroup.addTask {
1774+
try await Task.sleep(for: duration)
1775+
throw TimeoutError()
1776+
}
1777+
taskGroup.addTask {
1778+
return try await body()
1779+
}
1780+
for try await value in taskGroup {
1781+
taskGroup.cancelAll()
1782+
return value
1783+
}
1784+
throw CancellationError()
1785+
}
1786+
}

0 commit comments

Comments
 (0)