diff --git a/include/swift/AST/DiagnosticsSIL.def b/include/swift/AST/DiagnosticsSIL.def index d828ab556c022..032d274a73a4a 100644 --- a/include/swift/AST/DiagnosticsSIL.def +++ b/include/swift/AST/DiagnosticsSIL.def @@ -1119,6 +1119,32 @@ ERROR(regionbasedisolation_inout_sending_cannot_be_actor_isolated, none, NOTE(regionbasedisolation_inout_sending_cannot_be_actor_isolated_note, none, "%1 %0 risks causing races in between %1 uses and caller uses since caller assumes value is not actor isolated", (Identifier, StringRef)) +ERROR(regionbasedisolation_inout_sending_cannot_be_returned_param, none, + "'inout sending' parameter %0 cannot be returned", + (Identifier)) +ERROR(regionbasedisolation_inout_sending_cannot_be_returned_value, none, + "%0 cannot be returned", + (Identifier)) +ERROR(regionbasedisolation_inout_sending_cannot_be_returned_value_result, none, + "result of %kind0 cannot be returned", + (const ValueDecl *)) +NOTE(regionbasedisolation_inout_sending_cannot_be_returned_note_param, none, + "returning 'inout sending' parameter %0 risks concurrent access as caller assumes %0 and result can be sent to different isolation domains", + (Identifier)) +NOTE(regionbasedisolation_inout_sending_cannot_be_returned_note_value, none, + "returning %0 risks concurrent access to 'inout sending' parameter %1 as caller assumes %1 and result can be sent to different isolation domains", + (Identifier, Identifier)) +NOTE(regionbasedisolation_inout_sending_cannot_be_returned_note_return_value, none, + "returning result of %kind0 risks concurrent access to 'inout sending' parameter %1 as caller assumes %1 and result can be sent to different isolation domains", + (const ValueDecl *, Identifier)) +NOTE(regionbasedisolation_inout_sending_cannot_be_returned_note_actor_param, none, + "returning %0 risks concurrent access as caller assumes %0 is not actor-isolated and result is %1", (Identifier, StringRef)) +NOTE(regionbasedisolation_inout_sending_cannot_be_returned_note_actor_value, none, + "returning %0 risks concurrent access to 'inout sending' parameter %1 as caller assumes %1 is not actor-isolated and result is %2", + (Identifier, Identifier, StringRef)) +NOTE(regionbasedisolation_inout_sending_cannot_be_returned_note_actor_return_value, none, + "returning result of %kind0 risks concurrent access to 'inout sending' parameter %1 as caller assumes %1 is not actor-isolated and result is %2", + (const ValueDecl *, Identifier, StringRef)) //=== // Out Sending diff --git a/include/swift/SILOptimizer/Analysis/RegionAnalysis.h b/include/swift/SILOptimizer/Analysis/RegionAnalysis.h index 48bc902473812..190ae1d65693f 100644 --- a/include/swift/SILOptimizer/Analysis/RegionAnalysis.h +++ b/include/swift/SILOptimizer/Analysis/RegionAnalysis.h @@ -544,6 +544,10 @@ class RegionAnalysisFunctionInfo { bool isSupportedFunction() const { return supportedFunction; } + NullablePtr getBlockState(SILBasicBlock *block) const { + return blockStates->get(block); + } + using iterator = BasicBlockData::iterator; using const_iterator = BasicBlockData::const_iterator; using reverse_iterator = BasicBlockData::reverse_iterator; diff --git a/include/swift/SILOptimizer/Utils/PartitionOpError.def b/include/swift/SILOptimizer/Utils/PartitionOpError.def index 98253626e95ac..d4ef5b061dec6 100644 --- a/include/swift/SILOptimizer/Utils/PartitionOpError.def +++ b/include/swift/SILOptimizer/Utils/PartitionOpError.def @@ -52,6 +52,9 @@ PARTITION_OP_ERROR(InOutSendingNotInitializedAtExit) /// at end of function without being reinitialized with something disconnected. PARTITION_OP_ERROR(InOutSendingNotDisconnectedAtExit) +/// This is emitted when a concrete inout sending parameter is returned. +PARTITION_OP_ERROR(InOutSendingReturned) + /// Used to signify an "unknown code pattern" has occured while performing /// dataflow. /// diff --git a/include/swift/SILOptimizer/Utils/PartitionUtils.h b/include/swift/SILOptimizer/Utils/PartitionUtils.h index c1243dcd4fff8..d8e74bfce2076 100644 --- a/include/swift/SILOptimizer/Utils/PartitionUtils.h +++ b/include/swift/SILOptimizer/Utils/PartitionUtils.h @@ -1126,6 +1126,40 @@ class PartitionOpError { } }; + struct InOutSendingReturnedError { + const PartitionOp *op; + + /// The 'inout sending' parameter that caused the error to be emitted. + Element inoutSendingElement; + + /// The actual returned value. If we return the 'inout sending' parameter + /// then this will equal inoutSendingElement. + Element returnedValue; + + /// If we are actor isolated due to being in the same region as the out + /// parameter of a actor isolated method... this is that actor isolation. + SILDynamicMergedIsolationInfo isolationInfo; + + InOutSendingReturnedError(const PartitionOp &op, + Element inoutSendingElement, + Element returnedValue, + SILDynamicMergedIsolationInfo isolationInfo = {}) + : op(&op), inoutSendingElement(inoutSendingElement), + returnedValue(returnedValue), isolationInfo(isolationInfo) {} + + InOutSendingReturnedError(const PartitionOp &op, + Element inoutSendingElement, + SILDynamicMergedIsolationInfo isolationInfo = {}) + : InOutSendingReturnedError(op, inoutSendingElement, + inoutSendingElement, isolationInfo) {} + + void print(llvm::raw_ostream &os, RegionAnalysisValueMap &valueMap) const; + + SWIFT_DEBUG_DUMPER(dump(RegionAnalysisValueMap &valueMap)) { + print(llvm::dbgs(), valueMap); + } + }; + struct NonSendableIsolationCrossingResultError { const PartitionOp *op; @@ -1297,6 +1331,42 @@ struct PartitionOpEvaluator { return SILDynamicMergedIsolationInfo(); } + /// If \p region is not disconnected only because of an out parameter, return + /// that out parameter. We do not care about other non-disconnected parameters + /// since we always want to prefer the return error. + SILValue findNonDisconnectedOutParameterInRegion(Region region) const { + for (const auto &pair : p.range()) { + if (pair.second != region) + continue; + auto info = getIsolationRegionInfo(pair.first); + + // If we do not have any isolation info, then something bad + // happened. Return SILValue(). + if (!info) + return {}; + + // If we have something that is disconnected... continue. We do not care + // about this. + if (info.isDisconnected()) + continue; + + // See if we ahve an indirect out parameter... + if (auto value = asImpl().getIndirectOutParameter(pair.first)) { + return value; + } + + // If this was not an out parameter, return {}. + return {}; + } + + // After going over our loop, if result is not SILValue(), then we found + // that our region is not disconnected due only to a single 'indirect out' + // parameter. If SILValue() then we had all disconnected values. If we found + // multiple non-disconnected things, we would have bailed earlier in the + // loop itself. + return SILValue(); + } + bool isTaskIsolatedDerived(Element elt) const { return asImpl().isTaskIsolatedDerived(elt); } @@ -1534,7 +1604,9 @@ struct PartitionOpEvaluator { "Require PartitionOp's argument should already be tracked"); // First check if the region of our 'inout sending' element has been - // sent. In that case, we emit a special use after free error. + // sent. In that case, we emit a special use after free error so that the + // user knows that they need to reinitialize the 'inout sending' + // parameter. if (auto *sentOperandSet = p.getSentOperandSet(op.getOpArg1())) { for (auto sentOperand : sentOperandSet->data()) { handleError(InOutSendingNotInitializedAtExitError(op, op.getOpArg1(), @@ -1543,7 +1615,7 @@ struct PartitionOpEvaluator { return; } - // If we were not sent, check if our region is actor isolated. If so, + // If we were not sent, check if our region is not disconnected. If so, // error since we need a disconnected value in the inout parameter. Region inoutSendingRegion = p.getRegion(op.getOpArg1()); auto dynamicRegionIsolation = getIsolationRegionInfo(inoutSendingRegion); @@ -1554,12 +1626,82 @@ struct PartitionOpEvaluator { return; } - // Otherwise, emit the error if the dynamic region isolation is not - // disconnected. + auto handleDirectReturn = [&]() -> bool { + bool emittedDiagnostic = false; + + // For each value we are returning... + for (auto value : op.getSourceInst()->getOperandValues()) { + // Find its element and check if that element is in the same region as + // our inout sending param... + auto elt = asImpl().getElement(value); + if (!elt || inoutSendingRegion != p.getRegion(*elt)) + continue; + + emittedDiagnostic = true; + // Then check if our element is the same as our inoutSendingParam. In + // that case, we emit a special error that only refers to the + // inoutSendingParam as one entity. + // + // NOTE: This is taking advantage of us looking through loads when + // determining element identity. When that changes, this code will + // need to be updated to look through loads. + if (*elt == op.getOpArg1()) { + handleError(InOutSendingReturnedError(op, op.getOpArg1(), + dynamicRegionIsolation)); + continue; + } + + // Otherwise, we need to refer to a different value in the same region + // as the 'inout sending' parameter. Emit a special error. For that. + handleError(InOutSendingReturnedError(op, op.getOpArg1(), *elt, + dynamicRegionIsolation)); + } + + return emittedDiagnostic; + }; + + // Then check if our region isolated value is not disconnected... if (!dynamicRegionIsolation.isDisconnected()) { + // Before we emit the more general "inout sending" not disconnected at + // exit error... check if our dynamic region isolation is not + // disconnected since it is in the same region an out parameter. In that + // case we want to emit a special 'cannot return value' error. + if (auto outParam = + findNonDisconnectedOutParameterInRegion(inoutSendingRegion)) { + handleError(InOutSendingReturnedError(op, op.getOpArg1(), + getElement(outParam).value(), + dynamicRegionIsolation)); + return; + } + + // If we did not have an out parameter, see if we are returning a + // value that is in the region as our 'inout sending' parameter. + if (handleDirectReturn()) + return; + + // Otherwise, we emit the normal not disconnected at exit error. handleError(InOutSendingNotDisconnectedAtExitError( op, op.getOpArg1(), dynamicRegionIsolation)); + return; } + + // Ok, we have a disconnected value. We could still be returning a + // disconnected value in the same region as an 'inout sending' + // parameter. We cannot allow that since the caller considers 'inout + // sending' values to be in their own region on function return. So it + // would assume that it could potentially send the value in the 'inout + // sending' parameter and the return value to different isolation + // domains... allowing for races. + + // Even though we are disconnected, see if our SILFunction has an actor + // isolation. In that case, we want to use that since the direct return + // value will be inferred in the caller to have that isolation. + if (auto isolation = SILIsolationInfo::getFunctionIsolation( + op.getSourceInst()->getFunction())) { + dynamicRegionIsolation = {isolation}; + } + + handleDirectReturn(); return; } case PartitionOpKind::UnknownPatternError: @@ -1569,10 +1711,6 @@ struct PartitionOpEvaluator { // Then emit an unknown code pattern error. return handleError(UnknownCodePatternError(op)); case PartitionOpKind::NonSendableIsolationCrossingResult: { - // Grab the dynamic dataflow isolation information for our element's - // region. - Region region = p.getRegion(op.getOpArg1()); - // Then emit the error. return handleError( NonSendableIsolationCrossingResultError(op, op.getOpArg1())); @@ -1757,6 +1895,14 @@ struct PartitionOpEvaluatorBaseImpl : PartitionOpEvaluator { /// isolated value. bool isTaskIsolatedDerived(Element elt) const { return false; } + /// If \p elt maps to a representative that is an indirect out parameter, + /// return that value. + SILValue getIndirectOutParameter(Element elt) const { return {}; } + + /// If \p elt maps to a representative that is an 'inout sending' parameter + /// that returns that value. + SILValue getInOutSendingParameter(Element elt) const { return {}; } + /// By default, do nothing upon error. void handleError(PartitionOpError error) {} diff --git a/include/swift/SILOptimizer/Utils/SILIsolationInfo.h b/include/swift/SILOptimizer/Utils/SILIsolationInfo.h index 0aa008b5570bc..54f2916695a6a 100644 --- a/include/swift/SILOptimizer/Utils/SILIsolationInfo.h +++ b/include/swift/SILOptimizer/Utils/SILIsolationInfo.h @@ -546,6 +546,11 @@ class SILIsolationInfo { /// Infer isolation of conformances for the given instruction. static SILIsolationInfo getConformanceIsolation(SILInstruction *inst); + /// Return SILIsolationInfo based off of the attached ActorIsolation of \p + /// fn. If \p fn does not have an actor isolation set, returns an invalid + /// SILIsolationInfo. + static SILIsolationInfo getFunctionIsolation(SILFunction *fn); + /// A helper that is used to ensure that we treat certain builtin values as /// non-Sendable that the AST level otherwise thinks are non-Sendable. /// diff --git a/lib/SILOptimizer/Analysis/RegionAnalysis.cpp b/lib/SILOptimizer/Analysis/RegionAnalysis.cpp index 73c479e062405..28717628b29fd 100644 --- a/lib/SILOptimizer/Analysis/RegionAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/RegionAnalysis.cpp @@ -4115,7 +4115,10 @@ bool BlockPartitionState::recomputeExitFromEntry( } std::optional getElement(SILValue value) const { - return translator.getValueMap().getTrackableValue(value).value.getID(); + auto trackableValue = translator.getValueMap().getTrackableValue(value); + if (trackableValue.value.isSendable()) + return {}; + return trackableValue.value.getID(); } SILValue getRepresentative(SILValue value) const { diff --git a/lib/SILOptimizer/Mandatory/SendNonSendable.cpp b/lib/SILOptimizer/Mandatory/SendNonSendable.cpp index 588c06668499a..003259047b2d6 100644 --- a/lib/SILOptimizer/Mandatory/SendNonSendable.cpp +++ b/lib/SILOptimizer/Mandatory/SendNonSendable.cpp @@ -12,6 +12,8 @@ #define DEBUG_TYPE "send-non-sendable" +#include "swift/SIL/PrunedLiveness.h" + #include "swift/AST/ASTWalker.h" #include "swift/AST/Concurrency.h" #include "swift/AST/DiagnosticsSIL.h" @@ -641,6 +643,213 @@ class SendNonSendableImpl { } // namespace +//===----------------------------------------------------------------------===// +// MARK: Diagnostic Evaluator +//===----------------------------------------------------------------------===// + +namespace { + +struct DiagnosticEvaluator final + : PartitionOpEvaluatorBaseImpl { + RegionAnalysisFunctionInfo *info; + SmallFrozenMultiMap + &sendingOpToRequireInstMultiMap; + + /// An error that we know how to emit verbatim without needing to preprocess. + /// + /// A contrasting case here is the use after send error where we need to pair + /// sending operands to require insts. + SmallVectorImpl &foundVerbatimErrors; + + DiagnosticEvaluator(Partition &workingPartition, + RegionAnalysisFunctionInfo *info, + SmallFrozenMultiMap + &sendingOpToRequireInstMultiMap, + SmallVectorImpl &foundVerbatimErrors, + SendingOperandToStateMap &operandToStateMap) + : PartitionOpEvaluatorBaseImpl( + workingPartition, info->getOperandSetFactory(), operandToStateMap), + info(info), + sendingOpToRequireInstMultiMap(sendingOpToRequireInstMultiMap), + foundVerbatimErrors(foundVerbatimErrors) {} + + void handleLocalUseAfterSend(LocalUseAfterSendError error) const { + const auto &partitionOp = *error.op; + REGIONBASEDISOLATION_LOG(error.print(llvm::dbgs(), info->getValueMap())); + + // Ignore this if we are erroring on a mutable base of a Sendable value and + // if when we sent the value's region was not closure captured. + if (error.op->getOptions().containsOnly( + PartitionOp::Flag::RequireOfMutableBaseOfSendableValue) && + !operandToStateMap.get(error.sendingOp).isClosureCaptured) + return; + + sendingOpToRequireInstMultiMap.insert( + error.sendingOp, RequireInst::forUseAfterSend(partitionOp.getSourceInst())); + } + + void handleInOutSendingNotInitializedAtExitError( + InOutSendingNotInitializedAtExitError error) const { + const PartitionOp &partitionOp = *error.op; + Operand *sendingOp = error.sendingOp; + + REGIONBASEDISOLATION_LOG(error.print(llvm::dbgs(), info->getValueMap())); + + sendingOpToRequireInstMultiMap.insert( + sendingOp, RequireInst::forInOutReinitializationNeeded( + partitionOp.getSourceInst())); + } + + void handleUnknownCodePattern(UnknownCodePatternError error) const { + const PartitionOp &op = *error.op; + + if (shouldAbortOnUnknownPatternMatchError()) { + llvm::report_fatal_error( + "RegionIsolation: Aborting on unknown pattern match error"); + } + + diagnoseError(op.getSourceInst(), + diag::regionbasedisolation_unknown_pattern); + } + + void handleError(PartitionOpError error) { + switch (error.getKind()) { + case PartitionOpError::LocalUseAfterSend: { + return handleLocalUseAfterSend(error.getLocalUseAfterSendError()); + } + case PartitionOpError::InOutSendingNotDisconnectedAtExit: + case PartitionOpError::InOutSendingReturned: + case PartitionOpError::SentNeverSendable: + case PartitionOpError::AssignNeverSendableIntoSendingResult: + case PartitionOpError::NonSendableIsolationCrossingResult: + // We are going to process these later... but dump so we can see that we + // handled an error here. The rest of the explicit handlers will dump as + // appropriate if they want to emit an error here (some will squelch the + // error). + REGIONBASEDISOLATION_LOG(error.print(llvm::dbgs(), info->getValueMap())); + foundVerbatimErrors.emplace_back(error); + return; + case PartitionOpError::InOutSendingNotInitializedAtExit: { + return handleInOutSendingNotInitializedAtExitError( + error.getInOutSendingNotInitializedAtExitError()); + } + case PartitionOpError::UnknownCodePattern: { + return handleUnknownCodePattern(error.getUnknownCodePatternError()); + } + } + llvm_unreachable("Covered switch isn't covered?!"); + } + + bool isActorDerived(Element element) const { + return info->getValueMap().getIsolationRegion(element).isActorIsolated(); + } + + /// If \p element's representative is an indirect out parameter, return + /// that parameter. + SILValue getIndirectOutParameter(Element element) const { + auto rep = info->getValueMap().getRepresentativeValue(element); + if (!rep) + return {}; + if (auto value = dyn_cast_or_null(rep.maybeGetValue()); + value && value->getArgumentConvention().isIndirectOutParameter()) + return value; + return {}; + } + + SILValue getInOutSendingParameter(Element elt) const { + auto rep = info->getValueMap().getRepresentativeValue(elt); + if (!rep) + return {}; + if (auto value = dyn_cast_or_null(rep.maybeGetValue()); + value && value->getArgumentConvention().isInoutConvention() && + value->isSending()) + return value; + return {}; + } + + bool isTaskIsolatedDerived(Element element) const { + return info->getValueMap().getIsolationRegion(element).isTaskIsolated(); + } + + SILIsolationInfo::Kind hasSpecialDerivation(Element element) const { + return info->getValueMap().getIsolationRegion(element).getKind(); + } + + SILIsolationInfo getIsolationRegionInfo(Element element) const { + return info->getValueMap().getIsolationRegion(element); + } + + /// Only return an element if we are already tracking value and it is + /// non-Sendable. + /// + /// TODO: Can we return only + std::optional getElement(SILValue value) const { + auto trackableValue = info->getValueMap().getTrackableValue(value); + if (trackableValue.value.isSendable()) + return {}; + return trackableValue.value.getID(); + } + + SILValue getRepresentative(SILValue value) const { + return info->getValueMap() + .getTrackableValue(value) + .value.getRepresentative() + .maybeGetValue(); + } + + RepresentativeValue getRepresentativeValue(Element element) const { + return info->getValueMap().getRepresentativeValue(element); + } + + bool isClosureCaptured(Element element, Operand *op) const { + auto value = info->getValueMap().maybeGetRepresentative(element); + if (!value) + return false; + return info->isClosureCaptured(value, op); + } +}; + +} // namespace + +void SendNonSendableImpl::runDiagnosticEvaluator() { + // Then for each block... + REGIONBASEDISOLATION_LOG(llvm::dbgs() << "Walking blocks for diagnostics.\n"); + for (auto [block, blockState] : info->getRange()) { + REGIONBASEDISOLATION_LOG(llvm::dbgs() + << "|--> Block bb" << block.getDebugID() << "\n"); + + if (!blockState.getLiveness()) { + REGIONBASEDISOLATION_LOG(llvm::dbgs() << "Dead block... skipping!\n"); + continue; + } + + REGIONBASEDISOLATION_LOG( + llvm::dbgs() << "Entry Partition: "; + blockState.getEntryPartition().print(llvm::dbgs())); + + // Grab its entry partition and setup an evaluator for the partition that + // has callbacks that emit diagnsotics... + Partition workingPartition = blockState.getEntryPartition(); + DiagnosticEvaluator eval( + workingPartition, info, sendingOpToRequireInstMultiMap, + foundVerbatimErrors, info->getSendingOperandToStateMap()); + + // And then evaluate all of our partition ops on the entry partition. + for (auto &partitionOp : blockState.getPartitionOps()) { + eval.apply(partitionOp); + } + + REGIONBASEDISOLATION_LOG(llvm::dbgs() << "Exit Partition: "; + workingPartition.print(llvm::dbgs())); + } + + REGIONBASEDISOLATION_LOG(llvm::dbgs() + << "Finished walking blocks for diagnostics.\n"); + + // Now that we have found all of our sendingInsts/Requires emit errors. + sendingOpToRequireInstMultiMap.setFrozen(); +} + //===----------------------------------------------------------------------===// // MARK: UseAfterSend Diagnostic Inference //===----------------------------------------------------------------------===// @@ -2081,12 +2290,16 @@ bool SentNeverSendableDiagnosticInferrer::run() { } //===----------------------------------------------------------------------===// -// MARK: InOutSendingNotDisconnected Error Emitter +// MARK: InOutSendingReturnedError Error Emitter //===----------------------------------------------------------------------===// namespace { -class InOutSendingNotDisconnectedDiagnosticEmitter { +class InOutSendingReturnedDiagnosticEmitter { + /// A region analysis function info that we use if we need to determine which + /// incoming block edge had an error upon it. + RegionAnalysisFunctionInfo *raFuncInfo; + /// The function exiting inst where the 'inout sending' parameter was actor /// isolated. TermInst *functionExitingInst; @@ -2094,21 +2307,35 @@ class InOutSendingNotDisconnectedDiagnosticEmitter { /// The 'inout sending' param that we are emitting an error for. SILValue inoutSendingParam; - /// The dynamic actor isolated region info of our 'inout sending' value's - /// region at the terminator inst. - SILDynamicMergedIsolationInfo actorIsolatedRegionInfo; + /// The element number of the 'inout sending' param. + Element inoutSendingParamElement; + + /// If we did not return the 'inout sending' param directly but instead + /// returned something else in the same region. This is that value. + /// + /// If we actually returned the inout sending parameter this is SILValue(). + SILValue returnedValue; + + /// If we had a failure due to returning a value that is actor isolated due to + /// it being in the same region as an out parameter. THis is the actor + /// isolation. + SILDynamicMergedIsolationInfo isolationInfo; bool emittedErrorDiagnostic = false; public: - InOutSendingNotDisconnectedDiagnosticEmitter( - TermInst *functionExitingInst, SILValue inoutSendingParam, - SILDynamicMergedIsolationInfo actorIsolatedRegionInfo) - : functionExitingInst(functionExitingInst), + class LastValueEnum; + + InOutSendingReturnedDiagnosticEmitter( + RegionAnalysisFunctionInfo *raFuncInfo, TermInst *functionExitingInst, + SILValue inoutSendingParam, Element inoutSendingParamElement, + SILValue erroringValue, SILDynamicMergedIsolationInfo isolationInfo) + : raFuncInfo(raFuncInfo), functionExitingInst(functionExitingInst), inoutSendingParam(inoutSendingParam), - actorIsolatedRegionInfo(actorIsolatedRegionInfo) {} + inoutSendingParamElement(inoutSendingParamElement), + returnedValue(erroringValue), isolationInfo(isolationInfo) {} - ~InOutSendingNotDisconnectedDiagnosticEmitter() { + ~InOutSendingReturnedDiagnosticEmitter() { // If we were supposed to emit a diagnostic and didn't emit an unknown // pattern error. if (!emittedErrorDiagnostic) @@ -2135,6 +2362,112 @@ class InOutSendingNotDisconnectedDiagnosticEmitter { void emit(); + /// Called if we return the actual inout sending value. + void emitReturnInOutSendingError(SILDynamicMergedIsolationInfo isolationInfo, + SILLocation loc) { + // We should always be able to find a name for an inout sending param. If we + // do not, emit an unknown pattern error. + auto inoutSendingParamName = inferNameHelper(inoutSendingParam); + if (!inoutSendingParamName) { + return emitUnknownPatternError(); + } + + diagnoseError( + loc, diag::regionbasedisolation_inout_sending_cannot_be_returned_param, + *inoutSendingParamName) + .limitBehaviorIf(getBehaviorLimit()); + if (isolationInfo->isActorIsolated()) { + diagnoseNote( + loc, + diag:: + regionbasedisolation_inout_sending_cannot_be_returned_note_actor_param, + *inoutSendingParamName, + isolationInfo->printForDiagnostics(getFunction())); + return; + } + diagnoseNote( + loc, + diag::regionbasedisolation_inout_sending_cannot_be_returned_note_param, + *inoutSendingParamName); + } + + void emitValueError(SILValue value, + SILDynamicMergedIsolationInfo isolationInfo, + SILLocation loc) { + // We should always be able to find a name for an inout sending param. If we + // do not, emit an unknown pattern error. + auto inoutSendingParamName = inferNameHelper(inoutSendingParam); + if (!inoutSendingParamName) { + return emitUnknownPatternError(); + } + + std::optional erroringEltName = inferNameHelper(value); + if (!erroringEltName) { + return emitUnknownPatternError(); + } + + diagnoseError( + loc, diag::regionbasedisolation_inout_sending_cannot_be_returned_value, + *erroringEltName) + .limitBehaviorIf(getBehaviorLimit()); + if (isolationInfo->isActorIsolated()) { + diagnoseNote( + loc, + diag:: + regionbasedisolation_inout_sending_cannot_be_returned_note_actor_value, + *erroringEltName, *inoutSendingParamName, + isolationInfo->printForDiagnostics(getFunction())); + return; + } + diagnoseNote( + loc, + diag::regionbasedisolation_inout_sending_cannot_be_returned_note_value, + *erroringEltName, *inoutSendingParamName); + } + + /// Print \p value in a standard way. Allow for loc to override the specific + /// location used to emit the diagnostic fi non-standard. + void emitLastValueEnum(const LastValueEnum &value, + SILDynamicMergedIsolationInfo isolationInfo, + SILLocation loc = SILLocation::invalid()); + + /// Emit an error for use when we are processing the incoming value of a phi + /// argument or of the dynamic value of an indirect out parameter. + bool emitOutParamIncomingValueError(const LastValueEnum &value); + + void emitDeclRefError(SILDeclRef declRef, + SILDynamicMergedIsolationInfo isolationInfo, + SILLocation loc) { + // We should always be able to find a name for an inout sending param. If we + // do not, emit an unknown pattern error. + auto inoutSendingParamName = inferNameHelper(inoutSendingParam); + if (!inoutSendingParamName) { + return emitUnknownPatternError(); + } + + diagnoseError( + loc, + diag:: + regionbasedisolation_inout_sending_cannot_be_returned_value_result, + declRef.getAbstractFunctionDecl()) + .limitBehaviorIf(getBehaviorLimit()); + + if (isolationInfo->isActorIsolated()) { + diagnoseNote( + loc, + diag:: + regionbasedisolation_inout_sending_cannot_be_returned_note_actor_return_value, + declRef.getAbstractFunctionDecl(), *inoutSendingParamName, + isolationInfo.printForDiagnostics(getFunction())); + return; + } + diagnoseNote( + loc, + diag:: + regionbasedisolation_inout_sending_cannot_be_returned_note_return_value, + declRef.getAbstractFunctionDecl(), *inoutSendingParamName); + } + ASTContext &getASTContext() const { return functionExitingInst->getFunction()->getASTContext(); } @@ -2180,17 +2513,539 @@ class InOutSendingNotDisconnectedDiagnosticEmitter { } // namespace -void InOutSendingNotDisconnectedDiagnosticEmitter::emit() { - // We should always be able to find a name for an inout sending param. If we - // do not, emit an unknown pattern error. - auto varName = inferNameHelper(inoutSendingParam); - if (!varName) { - return emitUnknownPatternError(); - } +static SILValue lookThroughAccess(SILValue value) { + while (true) { + // We look through access, copies, and loads. + if (auto *bai = dyn_cast(value)) { + value = bai->getOperand(); + continue; + } - // Then emit the note with greater context. - auto descriptiveKindStr = - actorIsolatedRegionInfo.printForDiagnostics(getFunction()); + if (auto *cvi = dyn_cast(value)) { + value = cvi->getOperand(); + continue; + } + + if (auto *bbi = dyn_cast(value); + bbi && !bbi->isFromVarDecl()) { + value = bbi->getOperand(); + continue; + } + + if (auto *mvi = dyn_cast(value); + mvi && !mvi->isFromVarDecl()) { + value = mvi->getOperand(); + continue; + } + + if (auto *li = dyn_cast(value)) { + value = li->getOperand(); + continue; + } + + if (auto *lbi = dyn_cast(value)) { + value = lbi->getOperand(); + continue; + } + + return value; + } +} + +class InOutSendingReturnedDiagnosticEmitter::LastValueEnum { +public: + enum Kind { + None, + ApplySite, + CopyAddr, + Store, + Value, + ReturnTerm, + }; + +private: + Kind kind; + std::variant + value; + + LastValueEnum() : kind(Kind::None), value() {} + LastValueEnum(FullApplySite inst) : kind(Kind::ApplySite), value(inst) {} + LastValueEnum(SILValue value) : kind(Kind::Value), value(value) {} + LastValueEnum(CopyAddrInst *inst) : kind(Kind::CopyAddr), value(inst) {} + LastValueEnum(StoreInst *inst) : kind(Kind::Store), value(inst) {} + LastValueEnum(Operand *branchUse) : kind(Kind::ReturnTerm), value(branchUse) { + assert(isa(branchUse->getUser())); + assert(branchUse->getUser()->getLoc().getKind() == SILLocation::ReturnKind); + } + +public: + static LastValueEnum get(SILValue value); + static LastValueEnum get(SILInstruction *inst); + static LastValueEnum get(Operand *use); + static bool isSupported(Operand *use); + + operator bool() const { return getKind() != Kind::None; } + + Kind getKind() const { return kind; } + bool isApplySite() const { return getKind() == Kind::ApplySite; } + bool isValue() const { return getKind() == Kind::Value; } + bool isStore() const { return getKind() == Kind::Store; } + bool isCopyAddr() const { return getKind() == Kind::CopyAddr; } + + /// Is this a terminator instruction that is an incoming value to an epilogue + /// block and thus forms part of the return from a function. + bool isReturnTerm() const { return getKind() == Kind::ReturnTerm; } + + FullApplySite getFullApplySite() const { + return std::get(value); + } + SILDeclRef getDeclRef() const { + return getFullApplySite().getCalleeFunction()->getDeclRef(); + } + SILValue getValue() const { + switch (getKind()) { + case None: + case ApplySite: + return SILValue(); + case CopyAddr: + return getCopyAddr()->getAllOperands()[CopyLikeInstruction::Src].get(); + case Store: + return getStore()->getAllOperands()[CopyLikeInstruction::Src].get(); + case Value: + return std::get(value); + case ReturnTerm: + return std::get(value)->get(); + } + } + CopyAddrInst *getCopyAddr() const { return std::get(value); } + StoreInst *getStore() const { return std::get(value); } + Operand *getReturnTerm() const { return std::get(value); } + + SILBasicBlock *getParentBlock() const { + switch (getKind()) { + case None: + return nullptr; + case ApplySite: + return getFullApplySite()->getParent(); + case Value: + return getValue()->getParentBlock(); + case CopyAddr: + return getCopyAddr()->getParentBlock(); + case Store: + return getStore()->getParentBlock(); + case ReturnTerm: + return getReturnTerm()->getParentBlock(); + } + } + + SILInstruction *getDefiningInsertionPoint() const { + switch (getKind()) { + case None: + return nullptr; + case ApplySite: + return *getFullApplySite(); + case Value: + return getValue()->getDefiningInsertionPoint(); + case CopyAddr: + return getCopyAddr(); + case Store: + return getStore(); + case ReturnTerm: + return getReturnTerm()->getUser(); + } + } + + SILLocation getLoc() const { + switch (getKind()) { + case None: + return SILLocation::invalid(); + case ApplySite: + case Value: + case CopyAddr: + case Store: + case ReturnTerm: + return getDefiningInsertionPoint()->getLoc(); + } + } + + bool operator==(SILValue otherValue) const { + switch (getKind()) { + case None: + case ApplySite: + return false; + case CopyAddr: + case Store: + case Value: + case ReturnTerm: + return lookThroughAccess(getValue()) == lookThroughAccess(otherValue); + } + } + + static bool + findLastValuesForOutParam(SILFunctionArgument *fArg, + SmallVectorImpl &lastValues); + + void print(llvm::raw_ostream &os) const { + switch (getKind()) { + case None: + os << "none\n"; + return; + case ApplySite: + os << "apply site: " << *getFullApplySite(); + return; + case CopyAddr: + os << "copy_addr: " << *getCopyAddr(); + return; + case Store: + os << "store: " << *getStore(); + return; + case Value: + os << "value: " << *getValue(); + break; + case ReturnTerm: + os << "return term: " << *getReturnTerm()->getUser(); + } + } + + SWIFT_DEBUG_DUMP { print(llvm::dbgs()); } +}; + +InOutSendingReturnedDiagnosticEmitter::LastValueEnum +InOutSendingReturnedDiagnosticEmitter::LastValueEnum::get( + SILInstruction *user) { + if (auto *cai = dyn_cast(user)) { + return {cai}; + } + + if (auto *si = dyn_cast(user)) { + return {si}; + } + + if (auto fas = FullApplySite::isa(user)) { + return {fas}; + } + + return {}; +} + +InOutSendingReturnedDiagnosticEmitter::LastValueEnum +InOutSendingReturnedDiagnosticEmitter::LastValueEnum::get(Operand *use) { + if (auto value = get(use->getUser())) + return value; + + if (auto *ti = dyn_cast(use->getUser())) { + if (ti->getLoc().getKind() == SILLocation::ReturnKind) { + return {use}; + } + } + + return {}; +} + +bool InOutSendingReturnedDiagnosticEmitter::LastValueEnum::isSupported( + Operand *use) { + if (auto fas = FullApplySite::isa(use->getUser())) { + if (fas.isIndirectResultOperand(*use)) { + auto *fn = fas.getCalleeFunction(); + return fn && fn->getDeclRef(); + } + } + + if (auto *ti = dyn_cast(use->getUser())) { + if (ti->getLoc().getKind() == SILLocation::ReturnKind) { + return true; + } + } + + return isa(use->getUser()); +} + +InOutSendingReturnedDiagnosticEmitter::LastValueEnum +InOutSendingReturnedDiagnosticEmitter::LastValueEnum::get(SILValue value) { + if (auto *inst = value->getDefiningInstruction()) { + if (auto e = get(inst)) + return e; + } + + return {value}; +} + +void InOutSendingReturnedDiagnosticEmitter::emitLastValueEnum( + const LastValueEnum &value, SILDynamicMergedIsolationInfo isolationInfo, + SILLocation loc) { + switch (value.getKind()) { + case LastValueEnum::None: + llvm::report_fatal_error("Found .none enum elt"); + case LastValueEnum::ApplySite: + emitDeclRefError(value.getDeclRef(), isolationInfo, + loc ? loc : value.getLoc()); + return; + case LastValueEnum::Store: + case LastValueEnum::CopyAddr: + emitValueError(value.getValue(), isolationInfo, loc ? loc : value.getLoc()); + return; + case LastValueEnum::Value: + emitValueError(value.getValue(), isolationInfo, + loc ? loc : functionExitingInst->getLoc()); + return; + case LastValueEnum::ReturnTerm: + emitValueError(value.getValue(), isolationInfo, loc ? loc : value.getLoc()); + return; + } + llvm::report_fatal_error("Should never hit this"); +} + +bool InOutSendingReturnedDiagnosticEmitter::emitOutParamIncomingValueError( + const LastValueEnum &finalValue) { + auto *block = finalValue.getParentBlock(); + auto state = raFuncInfo->getBlockState(block); + assert(state.isNonNull()); + + // Grab the exit partition of the block. We make a copy here on purpose + // since it /is/ possible for DiagnosticEvaluator to modify + auto workingExitPartition = state.get()->getExitPartition(); + + // See if given the exit partition of the block if we would emit an error + // when we execute an InOutSendingAtFunctionExit partition op. + SmallFrozenMultiMap sendingOpToRequireInstMultiMap; + SmallVector errors; + DiagnosticEvaluator evaluator(workingExitPartition, raFuncInfo, + sendingOpToRequireInstMultiMap, errors, + raFuncInfo->getSendingOperandToStateMap()); + PartitionOp op = PartitionOp::InOutSendingAtFunctionExit( + inoutSendingParamElement, finalValue.getDefiningInsertionPoint()); + evaluator.apply(op); + + // Check if we got an error. If we did not, then this is not one of the + // guilty code paths. Continue. + if (errors.empty()) { + return false; + } + + // Loop through the errors to find our InOutReturnedError. We emit one error + // per return... but we emit for multiple returns separate diagnostics. + for (auto err : errors) { + if (err.getKind() != PartitionOpError::InOutSendingReturned) + continue; + auto castError = err.getInOutSendingReturnedError(); + if (castError.inoutSendingElement != inoutSendingParamElement) + continue; + // Ok, we found an error. Lets emit it and return early. + if (finalValue == inoutSendingParam) { + emitReturnInOutSendingError(isolationInfo, finalValue.getLoc()); + return true; + } + + // Force us to use the location of the finalValue. We do not want to use the + // function exiting inst. + emitLastValueEnum(finalValue, isolationInfo, finalValue.getLoc()); + return true; + } + + return false; +} + +void InOutSendingReturnedDiagnosticEmitter::emit() { + // Check if we had a separate erroring value that is our returned value. If we + // do not then we just returned the 'inout sending' parameter. Emit a special + // message and return. + if (inoutSendingParam == returnedValue) { + return emitReturnInOutSendingError(isolationInfo, + functionExitingInst->getLoc()); + } + + // Before we do anything, see if we have a phi argument that is an epilogue + // phi. In such a case, we want to process the incoming values. + if (auto *phi = dyn_cast(returnedValue)) { + bool handledValue = false; + phi->visitIncomingPhiOperands([&](Operand *op) { + if (op->getUser()->getLoc().getKind() != SILLocation::ReturnKind) + return true; + handledValue |= + emitOutParamIncomingValueError(LastValueEnum::get(op->get())); + return true; + }); + if (handledValue) + return; + } + + // Check if we have an indirect out parameter as our erroring returned value. + auto *fArg = dyn_cast(returnedValue); + if (!fArg || !fArg->isIndirectResult()) { + // If we do not have one... emit a normal error. + return emitLastValueEnum(LastValueEnum::get(returnedValue), isolationInfo); + } + + SmallVector finalValues; + if (!LastValueEnum::findLastValuesForOutParam(fArg, finalValues)) + return emitLastValueEnum(LastValueEnum::get(returnedValue), isolationInfo); + + // If we have a single value, then we have found our value. + if (finalValues.size() == 1) { + if (finalValues[0] == inoutSendingParam) { + return emitReturnInOutSendingError(isolationInfo, + finalValues[0].getLoc()); + } + emitLastValueEnum(finalValues[0], isolationInfo); + return; + } + + // If we have multiple finalValues, then that means that we had multiple + // return values. In such a case, we must have a single epilog block + // that our finalValues jointly dominate. That means that we need to + // determine which block the error actually occured along and emit an + // error for the value in that block. We know we are going to emit an + // error, so we can spend more time finding the better diagnostic since + // we are going to fail. + for (auto finalValue : finalValues) { + emitOutParamIncomingValueError(finalValue); + } +} + +bool InOutSendingReturnedDiagnosticEmitter::LastValueEnum:: + findLastValuesForOutParam(SILFunctionArgument *fArg, + SmallVectorImpl &lastValues) { + assert(fArg->isIndirectResult()); + SmallVector visitedBlocks; + SSAPrunedLiveness prunedLiveRange(fArg->getFunction(), &visitedBlocks); + + // Look for copy_addr and store uses into fArg. They should all be complete + // stores. + prunedLiveRange.initializeDef(fArg); + for (auto *use : fArg->getUses()) { + if (LastValueEnum::isSupported(use)) { + prunedLiveRange.updateForUse(use->getUser(), false /*lifetime ending*/); + continue; + } + return false; + } + + PrunedLivenessBoundary boundary; + prunedLiveRange.computeBoundary(boundary); + + for (auto *user : boundary.lastUsers) { + if (auto e = LastValueEnum::get(user)) { + lastValues.emplace_back(e); + continue; + } + + llvm::report_fatal_error("Out of sync with earlier check"); + } + + return true; +} + +//===----------------------------------------------------------------------===// +// MARK: InOutSendingNotDisconnected Error Emitter +//===----------------------------------------------------------------------===// + +namespace { + +class InOutSendingNotDisconnectedDiagnosticEmitter { + /// The function exiting inst where the 'inout sending' parameter was actor + /// isolated. + TermInst *functionExitingInst; + + /// The 'inout sending' param that we are emitting an error for. + SILValue inoutSendingParam; + + /// The dynamic actor isolated region info of our 'inout sending' value's + /// region at the terminator inst. + SILDynamicMergedIsolationInfo actorIsolatedRegionInfo; + + bool emittedErrorDiagnostic = false; + +public: + InOutSendingNotDisconnectedDiagnosticEmitter( + TermInst *functionExitingInst, SILValue inoutSendingParam, + SILDynamicMergedIsolationInfo actorIsolatedRegionInfo) + : functionExitingInst(functionExitingInst), + inoutSendingParam(inoutSendingParam), + actorIsolatedRegionInfo(actorIsolatedRegionInfo) {} + + ~InOutSendingNotDisconnectedDiagnosticEmitter() { + // If we were supposed to emit a diagnostic and didn't emit an unknown + // pattern error. + if (!emittedErrorDiagnostic) + emitUnknownPatternError(); + } + + SILFunction *getFunction() const { return inoutSendingParam->getFunction(); } + + std::optional getBehaviorLimit() const { + return inoutSendingParam->getType().getConcurrencyDiagnosticBehavior( + getFunction()); + } + + void emitUnknownPatternError() { + if (shouldAbortOnUnknownPatternMatchError()) { + llvm::report_fatal_error( + "RegionIsolation: Aborting on unknown pattern match error"); + } + + diagnoseError(functionExitingInst, + diag::regionbasedisolation_unknown_pattern) + .limitBehaviorIf(getBehaviorLimit()); + } + + void emit(); + + ASTContext &getASTContext() const { + return functionExitingInst->getFunction()->getASTContext(); + } + + template + InFlightDiagnostic diagnoseError(SourceLoc loc, Diag diag, + U &&...args) { + emittedErrorDiagnostic = true; + return std::move(getASTContext() + .Diags.diagnose(loc, diag, std::forward(args)...) + .warnUntilSwiftVersion(6)); + } + + template + InFlightDiagnostic diagnoseError(SILLocation loc, Diag diag, + U &&...args) { + return diagnoseError(loc.getSourceLoc(), diag, std::forward(args)...); + } + + template + InFlightDiagnostic diagnoseError(SILInstruction *inst, Diag diag, + U &&...args) { + return diagnoseError(inst->getLoc(), diag, std::forward(args)...); + } + + template + InFlightDiagnostic diagnoseNote(SourceLoc loc, Diag diag, U &&...args) { + return getASTContext().Diags.diagnose(loc, diag, std::forward(args)...); + } + + template + InFlightDiagnostic diagnoseNote(SILLocation loc, Diag diag, + U &&...args) { + return diagnoseNote(loc.getSourceLoc(), diag, std::forward(args)...); + } + + template + InFlightDiagnostic diagnoseNote(SILInstruction *inst, Diag diag, + U &&...args) { + return diagnoseNote(inst->getLoc(), diag, std::forward(args)...); + } +}; + +} // namespace + +void InOutSendingNotDisconnectedDiagnosticEmitter::emit() { + // We should always be able to find a name for an inout sending param. If we + // do not, emit an unknown pattern error. + auto varName = inferNameHelper(inoutSendingParam); + if (!varName) { + return emitUnknownPatternError(); + } + + // Then emit the note with greater context. + auto descriptiveKindStr = + actorIsolatedRegionInfo.printForDiagnostics(getFunction()); diagnoseError( functionExitingInst, @@ -2643,182 +3498,6 @@ void NonSendableIsolationCrossingResultDiagnosticEmitter::emit() { } } -//===----------------------------------------------------------------------===// -// MARK: Diagnostic Evaluator -//===----------------------------------------------------------------------===// - -namespace { - -struct DiagnosticEvaluator final - : PartitionOpEvaluatorBaseImpl { - RegionAnalysisFunctionInfo *info; - SmallFrozenMultiMap - &sendingOpToRequireInstMultiMap; - - /// An error that we know how to emit verbatim without needing to preprocess. - /// - /// A contrasting case here is the use after send error where we need to pair - /// sending operands to require insts. - SmallVectorImpl &foundVerbatimErrors; - - DiagnosticEvaluator(Partition &workingPartition, - RegionAnalysisFunctionInfo *info, - SmallFrozenMultiMap - &sendingOpToRequireInstMultiMap, - SmallVectorImpl &foundVerbatimErrors, - SendingOperandToStateMap &operandToStateMap) - : PartitionOpEvaluatorBaseImpl( - workingPartition, info->getOperandSetFactory(), operandToStateMap), - info(info), - sendingOpToRequireInstMultiMap(sendingOpToRequireInstMultiMap), - foundVerbatimErrors(foundVerbatimErrors) {} - - void handleLocalUseAfterSend(LocalUseAfterSendError error) const { - const auto &partitionOp = *error.op; - REGIONBASEDISOLATION_LOG(error.print(llvm::dbgs(), info->getValueMap())); - - // Ignore this if we are erroring on a mutable base of a Sendable value and - // if when we sent the value's region was not closure captured. - if (error.op->getOptions().containsOnly( - PartitionOp::Flag::RequireOfMutableBaseOfSendableValue) && - !operandToStateMap.get(error.sendingOp).isClosureCaptured) - return; - - sendingOpToRequireInstMultiMap.insert( - error.sendingOp, RequireInst::forUseAfterSend(partitionOp.getSourceInst())); - } - - void handleInOutSendingNotInitializedAtExitError( - InOutSendingNotInitializedAtExitError error) const { - const PartitionOp &partitionOp = *error.op; - Operand *sendingOp = error.sendingOp; - - REGIONBASEDISOLATION_LOG(error.print(llvm::dbgs(), info->getValueMap())); - - sendingOpToRequireInstMultiMap.insert( - sendingOp, RequireInst::forInOutReinitializationNeeded( - partitionOp.getSourceInst())); - } - - void handleUnknownCodePattern(UnknownCodePatternError error) const { - const PartitionOp &op = *error.op; - - if (shouldAbortOnUnknownPatternMatchError()) { - llvm::report_fatal_error( - "RegionIsolation: Aborting on unknown pattern match error"); - } - - diagnoseError(op.getSourceInst(), - diag::regionbasedisolation_unknown_pattern); - } - - void handleError(PartitionOpError error) { - switch (error.getKind()) { - case PartitionOpError::LocalUseAfterSend: { - return handleLocalUseAfterSend(error.getLocalUseAfterSendError()); - } - case PartitionOpError::InOutSendingNotDisconnectedAtExit: - case PartitionOpError::SentNeverSendable: - case PartitionOpError::AssignNeverSendableIntoSendingResult: - case PartitionOpError::NonSendableIsolationCrossingResult: - // We are going to process these later... but dump so we can see that we - // handled an error here. The rest of the explicit handlers will dump as - // appropriate if they want to emit an error here (some will squelch the - // error). - REGIONBASEDISOLATION_LOG(error.print(llvm::dbgs(), info->getValueMap())); - foundVerbatimErrors.emplace_back(error); - return; - case PartitionOpError::InOutSendingNotInitializedAtExit: { - return handleInOutSendingNotInitializedAtExitError( - error.getInOutSendingNotInitializedAtExitError()); - } - case PartitionOpError::UnknownCodePattern: { - return handleUnknownCodePattern(error.getUnknownCodePatternError()); - } - } - llvm_unreachable("Covered switch isn't covered?!"); - } - - bool isActorDerived(Element element) const { - return info->getValueMap().getIsolationRegion(element).isActorIsolated(); - } - - bool isTaskIsolatedDerived(Element element) const { - return info->getValueMap().getIsolationRegion(element).isTaskIsolated(); - } - - SILIsolationInfo::Kind hasSpecialDerivation(Element element) const { - return info->getValueMap().getIsolationRegion(element).getKind(); - } - - SILIsolationInfo getIsolationRegionInfo(Element element) const { - return info->getValueMap().getIsolationRegion(element); - } - - std::optional getElement(SILValue value) const { - return info->getValueMap().getTrackableValue(value).value.getID(); - } - - SILValue getRepresentative(SILValue value) const { - return info->getValueMap() - .getTrackableValue(value) - .value.getRepresentative() - .maybeGetValue(); - } - - RepresentativeValue getRepresentativeValue(Element element) const { - return info->getValueMap().getRepresentativeValue(element); - } - - bool isClosureCaptured(Element element, Operand *op) const { - auto value = info->getValueMap().maybeGetRepresentative(element); - if (!value) - return false; - return info->isClosureCaptured(value, op); - } -}; - -} // namespace - -void SendNonSendableImpl::runDiagnosticEvaluator() { - // Then for each block... - REGIONBASEDISOLATION_LOG(llvm::dbgs() << "Walking blocks for diagnostics.\n"); - for (auto [block, blockState] : info->getRange()) { - REGIONBASEDISOLATION_LOG(llvm::dbgs() - << "|--> Block bb" << block.getDebugID() << "\n"); - - if (!blockState.getLiveness()) { - REGIONBASEDISOLATION_LOG(llvm::dbgs() << "Dead block... skipping!\n"); - continue; - } - - REGIONBASEDISOLATION_LOG( - llvm::dbgs() << "Entry Partition: "; - blockState.getEntryPartition().print(llvm::dbgs())); - - // Grab its entry partition and setup an evaluator for the partition that - // has callbacks that emit diagnsotics... - Partition workingPartition = blockState.getEntryPartition(); - DiagnosticEvaluator eval( - workingPartition, info, sendingOpToRequireInstMultiMap, - foundVerbatimErrors, info->getSendingOperandToStateMap()); - - // And then evaluate all of our partition ops on the entry partition. - for (auto &partitionOp : blockState.getPartitionOps()) { - eval.apply(partitionOp); - } - - REGIONBASEDISOLATION_LOG(llvm::dbgs() << "Exit Partition: "; - workingPartition.print(llvm::dbgs())); - } - - REGIONBASEDISOLATION_LOG(llvm::dbgs() - << "Finished walking blocks for diagnostics.\n"); - - // Now that we have found all of our sendingInsts/Requires emit errors. - sendingOpToRequireInstMultiMap.setFrozen(); -} - //===----------------------------------------------------------------------===// // MARK: Top Level Entrypoint //===----------------------------------------------------------------------===// @@ -2853,6 +3532,21 @@ void SendNonSendableImpl::emitVerbatimErrors() { emitter.emit(); continue; } + case PartitionOpError::InOutSendingReturned: { + auto error = erasedError.getInOutSendingReturnedError(); + auto inoutSendingVal = + info->getValueMap().getRepresentative(error.inoutSendingElement); + auto returnedValue = + info->getValueMap().getRepresentative(error.returnedValue); + + REGIONBASEDISOLATION_LOG(error.print(llvm::dbgs(), info->getValueMap())); + + InOutSendingReturnedDiagnosticEmitter emitter( + info, cast(error.op->getSourceInst()), inoutSendingVal, + error.inoutSendingElement, returnedValue, error.isolationInfo); + emitter.emit(); + continue; + } case PartitionOpError::SentNeverSendable: { auto e = erasedError.getSentNeverSendableError(); REGIONBASEDISOLATION_LOG(e.print(llvm::dbgs(), info->getValueMap())); diff --git a/lib/SILOptimizer/Utils/PartitionUtils.cpp b/lib/SILOptimizer/Utils/PartitionUtils.cpp index 55a75e42f548c..0974dcc9fcd5a 100644 --- a/lib/SILOptimizer/Utils/PartitionUtils.cpp +++ b/lib/SILOptimizer/Utils/PartitionUtils.cpp @@ -102,6 +102,15 @@ void PartitionOpError::NonSendableIsolationCrossingResultError::print( << '\n'; } +void PartitionOpError::InOutSendingReturnedError::print( + llvm::raw_ostream &os, RegionAnalysisValueMap &valueMap) const { + os << " Emitting Error. Kind: InOutSendingReturnedError!\n" + << " ID: %%" << inoutSendingElement << '\n' + << " Rep: " << valueMap.getRepresentativeValue(inoutSendingElement) + << " Returned Value ID: %%" << returnedValue << '\n' + << " Rep: " << valueMap.getRepresentativeValue(returnedValue); +} + //===----------------------------------------------------------------------===// // MARK: PartitionOp //===----------------------------------------------------------------------===// diff --git a/lib/SILOptimizer/Utils/SILIsolationInfo.cpp b/lib/SILOptimizer/Utils/SILIsolationInfo.cpp index 3feb4720b13d6..91fc48c5634ca 100644 --- a/lib/SILOptimizer/Utils/SILIsolationInfo.cpp +++ b/lib/SILOptimizer/Utils/SILIsolationInfo.cpp @@ -1629,6 +1629,24 @@ bool SILIsolationInfo::isNonSendableType(SILType type, SILFunction *fn) { return *behavior != DiagnosticBehavior::Ignore; } +SILIsolationInfo SILIsolationInfo::getFunctionIsolation(SILFunction *fn) { + auto isolation = fn->getActorIsolation(); + if (!isolation) + return {}; + + if (isolation->isGlobalActor()) { + return SILIsolationInfo::getGlobalActorIsolated( + SILValue(), isolation->getGlobalActor()); + } + + if (isolation->isActorInstanceIsolated()) { + return SILIsolationInfo::getActorInstanceIsolated( + SILValue(), cast(fn->maybeGetIsolatedArgument())); + } + + return {}; +} + //===----------------------------------------------------------------------===// // MARK: ActorInstance //===----------------------------------------------------------------------===// diff --git a/test/Concurrency/transfernonsendable_sending_params.swift b/test/Concurrency/transfernonsendable_sending_params.swift index 1f5e57335f86a..f8024bc575571 100644 --- a/test/Concurrency/transfernonsendable_sending_params.swift +++ b/test/Concurrency/transfernonsendable_sending_params.swift @@ -39,6 +39,8 @@ final class FinalKlassWithNonSendableStructPair { } func useValue(_ t: T) {} +func useValueAndReturnGeneric(_ t: T) -> T { t } +func useNonSendableKlassAndReturn(_ t: NonSendableKlass) -> NonSendableKlass { t } func getAny() -> Any { fatalError() } actor Custom { @@ -56,6 +58,8 @@ struct CustomActor { func throwingFunction() throws { fatalError() } +func getBool() -> Bool { false } + func transferArg(_ x: sending NonSendableKlass) { } @@ -111,7 +115,6 @@ func testSimpleTransferUseOfOtherParamNoError2() { } @MainActor func transferToMain2(_ x: sending NonSendableKlass, _ y: NonSendableKlass, _ z: NonSendableKlass) async { - } // TODO: How to test this? @@ -515,6 +518,2422 @@ func testWrongIsolationGlobalIsolation(_ x: inout sending NonSendableKlass) { } // expected-warning {{'inout sending' parameter 'x' cannot be main actor-isolated at end of function}} // expected-note @-1 {{main actor-isolated 'x' risks causing races in between main actor-isolated uses and caller uses since caller assumes value is not actor isolated}} +////////////////////////////////////// +// MARK: Return Inout Sending Tests // +////////////////////////////////////// + +func returnInOutSendingDirectly(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'inout sending' parameter 'x' risks concurrent access as caller assumes 'x' and result can be sent to different isolation domains}} +} + +func returnInOutSendingRegionLet(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + let y = x + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} +} + +func returnInOutSendingRegionVar(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + var y = x + y = x + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} +} + + +func returnInOutSendingViaHelper(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + let y = x + return useNonSendableKlassAndReturn(y) // expected-warning {{result of global function 'useNonSendableKlassAndReturn' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} +} + +func returnInOutSendingHelperDirect(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + return useNonSendableKlassAndReturn(x) // expected-warning {{result of global function 'useNonSendableKlassAndReturn' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} +} + +func returnInOutSendingDirectlyIf(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + if getBool() { + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'inout sending' parameter 'x' risks concurrent access as caller assumes 'x' and result can be sent to different isolation domains}} + } + fatalError() +} + +func returnInOutSendingRegionLetIf(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + let y = x + if getBool() { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } else { + print(y) + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'inout sending' parameter 'x' risks concurrent access as caller assumes 'x' and result can be sent to different isolation domains}} + } +} + +func returnInOutSendingRegionVarIf(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + var y = x + y = x + if getBool() { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } + fatalError() +} + +func returnInOutSendingViaHelperIf(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + let y = x + if getBool() { + return useNonSendableKlassAndReturn(y) // expected-warning {{result of global function 'useNonSendableKlassAndReturn' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } else { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } +} + +func returnInOutSendingHelperDirectIf(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + if getBool() { + return useNonSendableKlassAndReturn(x) // expected-warning {{result of global function 'useNonSendableKlassAndReturn' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } else { + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'inout sending' parameter 'x' risks concurrent access as caller assumes 'x' and result can be sent to different isolation domains}} + } +} + +func returnInOutSendingViaHelperVarIf(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + var y = x + y = x + if getBool() { + return useNonSendableKlassAndReturn(y) // expected-warning {{result of global function 'useNonSendableKlassAndReturn' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } else { + print(y) + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } +} + +func returnInOutSendingDirectlyElse(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + if getBool() { + print(x) + fatalError() + } else { + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'inout sending' parameter 'x' risks concurrent access as caller assumes 'x' and result can be sent to different isolation domains}} + } +} + +func returnInOutSendingRegionLetElse(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + let y = x + if getBool() { + print(y) + fatalError() + } else { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } +} + +func returnInOutSendingRegionVarElse(_ x: inout sending NonSendableKlass, z: NonSendableKlass) -> NonSendableKlass { + var y = x + y = x + if getBool() { + print(y) + return z + } else { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } +} + +func returnInOutSendingViaHelperElse(_ x: inout sending NonSendableKlass, _ z: NonSendableKlass) -> NonSendableKlass { + let y = x + if getBool() { + print(y) + return z + } else { + return useNonSendableKlassAndReturn(y) // expected-warning {{result of global function 'useNonSendableKlassAndReturn' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } +} + +func returnInOutSendingHelperDirectElse(_ x: inout sending NonSendableKlass, _ z: NonSendableKlass) -> NonSendableKlass { + if getBool() { + print(x) + return z + } else { + return useNonSendableKlassAndReturn(x) // expected-warning {{result of global function 'useNonSendableKlassAndReturn' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } +} + +func returnInOutSendingViaHelperVarElse(_ x: inout sending NonSendableKlass, _ z: NonSendableKlass) -> NonSendableKlass { + var y = x + y = x + if getBool() { + print(y) + return z + } else { + return useNonSendableKlassAndReturn(y) // expected-warning {{result of global function 'useNonSendableKlassAndReturn' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } +} + +func returnInOutSendingDirectlyFor(_ x: inout sending NonSendableKlass, _ z: NonSendableKlass) -> NonSendableKlass { + for _ in 0..<1 { + if getBool() { + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'inout sending' parameter 'x' risks concurrent access as caller assumes 'x' and result can be sent to different isolation domains}} + } + } + print(x) + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'inout sending' parameter 'x' risks concurrent access as caller assumes 'x' and result can be sent to different isolation domains}} +} + +func returnInOutSendingDirectlyFor2(_ x: inout sending NonSendableKlass, _ z: NonSendableKlass) -> NonSendableKlass { + for _ in 0..<1 { + if getBool() { + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'inout sending' parameter 'x' risks concurrent access as caller assumes 'x' and result can be sent to different isolation domains}} + } + } + print(x) + return z +} + +func returnInOutSendingRegionLetFor(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + let y = x + for _ in 0..<1 { + if getBool() { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } + } + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'inout sending' parameter 'x' risks concurrent access as caller assumes 'x' and result can be sent to different isolation domains}} +} + +func returnInOutSendingRegionLetFor2(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + let y = x + for _ in 0..<1 { + if getBool() { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } + } + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} +} + +func returnInOutSendingRegionLetFor3(_ x: inout sending NonSendableKlass, _ z: NonSendableKlass) -> NonSendableKlass { + let y = x + for _ in 0..<1 { + if getBool() { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } + } + return z +} + +func returnInOutSendingRegionVarFor(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + var y = x + y = x + for _ in 0..<1 { + if getBool() { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } + } + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} +} + +func returnInOutSendingRegionVarFor2(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + var y = x + y = x + for _ in 0..<1 { + if getBool() { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } + } + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'inout sending' parameter 'x' risks concurrent access as caller assumes 'x' and result can be sent to different isolation domains}} +} + +func returnInOutSendingRegionVarFor3(_ x: inout sending NonSendableKlass, _ z: NonSendableKlass) -> NonSendableKlass { + var y = x + y = x + for _ in 0..<1 { + if getBool() { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } + } + return z +} + +func returnInOutSendingViaHelperFor(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + let y = x + for _ in 0..<1 { + if getBool() { + return useNonSendableKlassAndReturn(y) // expected-warning {{result of global function 'useNonSendableKlassAndReturn' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } + } + print(y) + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'inout sending' parameter 'x' risks concurrent access as caller assumes 'x' and result can be sent to different isolation domains}} +} + +func returnInOutSendingViaHelperFor2(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + let y = x + for _ in 0..<1 { + if getBool() { + return useNonSendableKlassAndReturn(y) // expected-warning {{result of global function 'useNonSendableKlassAndReturn' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } + } + print(y) + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} +} + +func returnInOutSendingHelperDirectFor(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + for _ in 0..<1 { + if getBool() { + return useNonSendableKlassAndReturn(x) // expected-warning {{result of global function 'useNonSendableKlassAndReturn' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } + } + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'inout sending' parameter 'x' risks concurrent access as caller assumes 'x' and result can be sent to different isolation domains}} +} + +func returnInOutSendingViaHelperVarFor(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + var y = x + y = x + for _ in 0..<1 { + if getBool() { + return useNonSendableKlassAndReturn(y) // expected-warning {{result of global function 'useNonSendableKlassAndReturn' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } + } + print(y) + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} +} + +func returnInOutSendingDirectlyGuard(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + guard getBool() else { + print(x) + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'inout sending' parameter 'x' risks concurrent access as caller assumes 'x' and result can be sent to different isolation domains}} + } + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'inout sending' parameter 'x' risks concurrent access as caller assumes 'x' and result can be sent to different isolation domains}} +} + +func returnInOutSendingRegionLetGuard(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + let y = x + guard getBool() else { + print(y) + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} +} + +func returnInOutSendingRegionVarGuard(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + var y = x + y = x + guard getBool() else { + print(y) + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'inout sending' parameter 'x' risks concurrent access as caller assumes 'x' and result can be sent to different isolation domains}} + } + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} +} + +func returnInOutSendingViaHelperGuard(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + let y = x + guard getBool() else { + print(y) + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } + return useNonSendableKlassAndReturn(y) // expected-warning {{result of global function 'useNonSendableKlassAndReturn' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} +} + +func returnInOutSendingHelperDirectGuard(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + guard getBool() else { + print(x) + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'inout sending' parameter 'x' risks concurrent access as caller assumes 'x' and result can be sent to different isolation domains}} + } + return useNonSendableKlassAndReturn(x) // expected-warning {{result of global function 'useNonSendableKlassAndReturn' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} +} + +func returnInOutSendingViaHelperVarGuard(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + var y = x + y = x + guard getBool() else { + print(y) + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } + return useNonSendableKlassAndReturn(y) // expected-warning {{result of global function 'useNonSendableKlassAndReturn' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} +} + +func returnInOutSendingViaHelperVar(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + var y = x + y = x + return useNonSendableKlassAndReturn(y) // expected-warning {{result of global function 'useNonSendableKlassAndReturn' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} +} + +func returnGenericInOutSendingDirectly(_ x: inout sending T) -> T { + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'inout sending' parameter 'x' risks concurrent access as caller assumes 'x' and result can be sent to different isolation domains}} +} + +func returnGenericInOutSendingRegionLet(_ x: inout sending T) -> T { + let y = x + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} +} + +func returnGenericInOutSendingRegionVar(_ x: inout sending T) -> T { + var y = x + y = x + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} +} + +func returnGenericInOutSendingViaHelper(_ x: inout sending T) -> T { + let y = x + return useValueAndReturnGeneric(y) // expected-warning {{result of global function 'useValueAndReturnGeneric' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useValueAndReturnGeneric' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} +} + +func returnGenericInOutSendingHelperDirect(_ x: inout sending T) -> T { + return useValueAndReturnGeneric(x) // expected-warning {{result of global function 'useValueAndReturnGeneric' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useValueAndReturnGeneric' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} +} + +func returnGenericInOutSendingViaHelperVar(_ x: inout sending T) -> T { + var y = x + y = x + return useValueAndReturnGeneric(y) // expected-warning {{result of global function 'useValueAndReturnGeneric' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useValueAndReturnGeneric' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} +} + +func returnGenericInOutSendingDirectlyIf(_ x: inout sending T) -> T { + if getBool() { + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'inout sending' parameter 'x' risks concurrent access as caller assumes 'x' and result can be sent to different isolation domains}} + } + fatalError() +} + +func returnGenericInOutSendingRegionLetIf(_ x: inout sending T) -> T { + let y = x + if getBool() { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } else { + print(y) + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'inout sending' parameter 'x' risks concurrent access as caller assumes 'x' and result can be sent to different isolation domains}} + } +} + +func returnGenericInOutSendingRegionVarIf(_ x: inout sending T) -> T { + var y = x + y = x + if getBool() { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } + fatalError() +} + +func returnGenericInOutSendingViaHelperIf(_ x: inout sending T) -> T { + let y = x + if getBool() { + return useValueAndReturnGeneric(y) // expected-warning {{result of global function 'useValueAndReturnGeneric' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useValueAndReturnGeneric' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } else { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } +} + +func returnGenericInOutSendingHelperDirectIf(_ x: inout sending T) -> T { + if getBool() { + return useValueAndReturnGeneric(x) // expected-warning {{result of global function 'useValueAndReturnGeneric' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useValueAndReturnGeneric' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } else { + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'inout sending' parameter 'x' risks concurrent access as caller assumes 'x' and result can be sent to different isolation domains}} + } +} + +func returnGenericInOutSendingViaHelperVarIf(_ x: inout sending T) -> T { + var y = x + y = x + if getBool() { + return useValueAndReturnGeneric(y) // expected-warning {{result of global function 'useValueAndReturnGeneric' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useValueAndReturnGeneric' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } else { + print(y) + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } +} + +func returnGenericInOutSendingDirectlyElse(_ x: inout sending T) -> T { + if getBool() { + print(x) + fatalError() + } else { + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'inout sending' parameter 'x' risks concurrent access as caller assumes 'x' and result can be sent to different isolation domains}} + } +} + +func returnGenericInOutSendingRegionLetElse(_ x: inout sending T) -> T { + let y = x + if getBool() { + print(y) + fatalError() + } else { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } +} + +func returnGenericInOutSendingRegionVarElse(_ x: inout sending T, z: T) -> T { + var y = x + y = x + if getBool() { + print(y) + return z + } else { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } +} + +func returnGenericInOutSendingViaHelperElse(_ x: inout sending T, _ z: T) -> T { + let y = x + if getBool() { + print(y) + return z + } else { + return useValueAndReturnGeneric(y) // expected-warning {{result of global function 'useValueAndReturnGeneric' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useValueAndReturnGeneric' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } +} + +func returnGenericInOutSendingHelperDirectElse(_ x: inout sending T, _ z: T) -> T { + if getBool() { + print(x) + return z + } else { + return useValueAndReturnGeneric(x) // expected-warning {{result of global function 'useValueAndReturnGeneric' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useValueAndReturnGeneric' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } +} + +func returnGenericInOutSendingViaHelperVarElse(_ x: inout sending T, _ z: T) -> T { + var y = x + y = x + if getBool() { + print(y) + return z + } else { + return useValueAndReturnGeneric(y) // expected-warning {{result of global function 'useValueAndReturnGeneric' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useValueAndReturnGeneric' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } +} + +func returnGenericInOutSendingDirectlyFor(_ x: inout sending T, _ z: T) -> T { + for _ in 0..<1 { + if getBool() { + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'inout sending' parameter 'x' risks concurrent access as caller assumes 'x' and result can be sent to different isolation domains}} + } + } + print(x) + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'inout sending' parameter 'x' risks concurrent access as caller assumes 'x' and result can be sent to different isolation domains}} +} + +func returnGenericInOutSendingDirectlyFor2(_ x: inout sending T, _ z: T) -> T { + for _ in 0..<1 { + if getBool() { + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'inout sending' parameter 'x' risks concurrent access as caller assumes 'x' and result can be sent to different isolation domains}} + } + } + print(x) + return z +} + +func returnGenericInOutSendingRegionLetFor(_ x: inout sending T) -> T { + let y = x + for _ in 0..<1 { + if getBool() { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } + } + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'inout sending' parameter 'x' risks concurrent access as caller assumes 'x' and result can be sent to different isolation domains}} +} + +func returnGenericInOutSendingRegionLetFor2(_ x: inout sending T) -> T { + let y = x + for _ in 0..<1 { + if getBool() { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } + } + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} +} + +func returnGenericInOutSendingRegionLetFor3(_ x: inout sending T, _ z: T) -> T { + let y = x + for _ in 0..<1 { + if getBool() { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } + } + return z +} + +func returnGenericInOutSendingRegionVarFor(_ x: inout sending T) -> T { + var y = x + y = x + for _ in 0..<1 { + if getBool() { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } + } + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} +} + +func returnGenericInOutSendingRegionVarFor2(_ x: inout sending T) -> T { + var y = x + y = x + for _ in 0..<1 { + if getBool() { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } + } + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'inout sending' parameter 'x' risks concurrent access as caller assumes 'x' and result can be sent to different isolation domains}} +} + +func returnGenericInOutSendingRegionVarFor3(_ x: inout sending T, _ z: T) -> T { + var y = x + y = x + for _ in 0..<1 { + if getBool() { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } + } + return z +} + +func returnGenericInOutSendingViaHelperFor(_ x: inout sending T) -> T { + let y = x + for _ in 0..<1 { + if getBool() { + return useValueAndReturnGeneric(y) // expected-warning {{result of global function 'useValueAndReturnGeneric' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useValueAndReturnGeneric' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } + } + print(y) + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'inout sending' parameter 'x' risks concurrent access as caller assumes 'x' and result can be sent to different isolation domains}} +} + +func returnGenericInOutSendingViaHelperFor2(_ x: inout sending T) -> T { + let y = x + for _ in 0..<1 { + if getBool() { + return useValueAndReturnGeneric(y) // expected-warning {{result of global function 'useValueAndReturnGeneric' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useValueAndReturnGeneric' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } + } + print(y) + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} +} + +func returnGenericInOutSendingHelperDirectFor(_ x: inout sending T) -> T { + for _ in 0..<1 { + if getBool() { + return useValueAndReturnGeneric(x) // expected-warning {{result of global function 'useValueAndReturnGeneric' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useValueAndReturnGeneric' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } + } + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'inout sending' parameter 'x' risks concurrent access as caller assumes 'x' and result can be sent to different isolation domains}} +} + +func returnGenericInOutSendingViaHelperVarFor(_ x: inout sending T) -> T { + var y = x + y = x + for _ in 0..<1 { + if getBool() { + return useValueAndReturnGeneric(y) // expected-warning {{result of global function 'useValueAndReturnGeneric' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useValueAndReturnGeneric' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } + } + print(y) + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} +} + +func returnGenericInOutSendingDirectlyGuard(_ x: inout sending T) -> T { + guard getBool() else { + print(x) + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'inout sending' parameter 'x' risks concurrent access as caller assumes 'x' and result can be sent to different isolation domains}} + } + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'inout sending' parameter 'x' risks concurrent access as caller assumes 'x' and result can be sent to different isolation domains}} +} + +func returnGenericInOutSendingRegionLetGuard(_ x: inout sending T) -> T { + let y = x + guard getBool() else { + print(y) + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} +} + +func returnGenericInOutSendingRegionVarGuard(_ x: inout sending T) -> T { + var y = x + y = x + guard getBool() else { + print(y) + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'inout sending' parameter 'x' risks concurrent access as caller assumes 'x' and result can be sent to different isolation domains}} + } + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} +} + +func returnGenericInOutSendingViaHelperGuard(_ x: inout sending T) -> T { + let y = x + guard getBool() else { + print(y) + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } + return useValueAndReturnGeneric(y) // expected-warning {{result of global function 'useValueAndReturnGeneric' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useValueAndReturnGeneric' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} +} + +func returnGenericInOutSendingHelperDirectGuard(_ x: inout sending T) -> T { + guard getBool() else { + print(x) + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'inout sending' parameter 'x' risks concurrent access as caller assumes 'x' and result can be sent to different isolation domains}} + } + return useValueAndReturnGeneric(x) // expected-warning {{result of global function 'useValueAndReturnGeneric' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useValueAndReturnGeneric' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} +} + +func returnGenericInOutSendingViaHelperVarGuard(_ x: inout sending T) -> T { + var y = x + y = x + guard getBool() else { + print(y) + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} + } + return useValueAndReturnGeneric(y) // expected-warning {{result of global function 'useValueAndReturnGeneric' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useValueAndReturnGeneric' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' and result can be sent to different isolation domains}} +} + +/////////////////////////////////////////////////// +// MARK: ReturnSendingInOutTestActor Actor Tests // +/////////////////////////////////////////////////// + +actor ReturnSendingInOutTestActor { + + func testInOutSendingReinit(_ x: inout sending NonSendableKlass) async { + await transferToMain(x) // expected-warning {{sending 'x' risks causing data races}} + // expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local actor-isolated uses}} + } // expected-note {{'inout sending' parameter must be reinitialized before function exit with a non-actor-isolated value}} + + func testInOutSendingReinit2(_ x: inout sending NonSendableKlass) async { + await transferToMain(x) + x = NonSendableKlass() + } + + func testInOutSendingReinit3(_ x: inout sending NonSendableKlass) async throws { + await transferToMain(x) // expected-warning {{sending 'x' risks causing data races}} + // expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local actor-isolated uses}} + + + try throwingFunction() // expected-note {{'inout sending' parameter must be reinitialized before function exit with a non-actor-isolated value}} + + x = NonSendableKlass() + } + + func testInOutSendingReinit4(_ x: inout sending NonSendableKlass) async throws { + await transferToMain(x) // expected-warning {{sending 'x' risks causing data races}} + // expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local actor-isolated uses}} + + + do { + try throwingFunction() + x = NonSendableKlass() + } catch { + throw MyError() // expected-note {{'inout sending' parameter must be reinitialized before function exit with a non-actor-isolated value}} + } + + x = NonSendableKlass() + } + + func testInOutSendingReinit5(_ x: inout sending NonSendableKlass) async throws { + await transferToMain(x) // expected-warning {{sending 'x' risks causing data races}} + // expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local actor-isolated uses}} + + + do { + try throwingFunction() + } catch { + throw MyError() // expected-note {{'inout sending' parameter must be reinitialized before function exit with a non-actor-isolated value}} + } + + x = NonSendableKlass() + } + + func testInOutSendingReinit6(_ x: inout sending NonSendableKlass) async throws { + await transferToMain(x) // expected-warning {{sending 'x' risks causing data races}} + // expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local actor-isolated uses}} + + + do { + try throwingFunction() + } catch { + throw MyError() // expected-note {{'inout sending' parameter must be reinitialized before function exit with a non-actor-isolated value}} + } + } // expected-note {{'inout sending' parameter must be reinitialized before function exit with a non-actor-isolated value}} + + func returnInOutSendingDirectly(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + + func returnInOutSendingRegionLet(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + let y = x + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + + func returnInOutSendingRegionVar(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + var y = x + y = x + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + + func returnInOutSendingViaHelper(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + let y = x + return useNonSendableKlassAndReturn(y) // expected-warning {{result of global function 'useNonSendableKlassAndReturn' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + + func returnInOutSendingHelperDirect(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + return useNonSendableKlassAndReturn(x) // expected-warning {{result of global function 'useNonSendableKlassAndReturn' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + + func returnInOutSendingDirectlyIf(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + if getBool() { + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + fatalError() + } + + func returnInOutSendingRegionLetIf(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + let y = x + if getBool() { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } else { + print(y) + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + } + + func returnInOutSendingRegionVarIf(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + var y = x + y = x + if getBool() { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + fatalError() + } + + func returnInOutSendingViaHelperIf(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + let y = x + if getBool() { + return useNonSendableKlassAndReturn(y) // expected-warning {{result of global function 'useNonSendableKlassAndReturn' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } else { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + } + + func returnInOutSendingHelperDirectIf(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + if getBool() { + return useNonSendableKlassAndReturn(x) // expected-warning {{result of global function 'useNonSendableKlassAndReturn' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } else { + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + } + + func returnInOutSendingViaHelperVarIf(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + var y = x + y = x + if getBool() { + return useNonSendableKlassAndReturn(y) // expected-warning {{result of global function 'useNonSendableKlassAndReturn' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } else { + print(y) + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + } + + func returnInOutSendingDirectlyElse(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + if getBool() { + print(x) + fatalError() + } else { + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + } + + func returnInOutSendingRegionLetElse(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + let y = x + if getBool() { + print(y) + fatalError() + } else { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + } + + func returnInOutSendingRegionVarElse(_ x: inout sending NonSendableKlass, z: NonSendableKlass) -> NonSendableKlass { + var y = x + y = x + if getBool() { + print(y) + return z + } else { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + } + + func returnInOutSendingViaHelperElse(_ x: inout sending NonSendableKlass, _ z: NonSendableKlass) -> NonSendableKlass { + let y = x + if getBool() { + print(y) + return z + } else { + return useNonSendableKlassAndReturn(y) // expected-warning {{result of global function 'useNonSendableKlassAndReturn' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + } + + func returnInOutSendingHelperDirectElse(_ x: inout sending NonSendableKlass, _ z: NonSendableKlass) -> NonSendableKlass { + if getBool() { + print(x) + return z + } else { + return useNonSendableKlassAndReturn(x) // expected-warning {{result of global function 'useNonSendableKlassAndReturn' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + } + + func returnInOutSendingViaHelperVarElse(_ x: inout sending NonSendableKlass, _ z: NonSendableKlass) -> NonSendableKlass { + var y = x + y = x + if getBool() { + print(y) + return z + } else { + return useNonSendableKlassAndReturn(y) // expected-warning {{result of global function 'useNonSendableKlassAndReturn' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + } + + func returnInOutSendingDirectlyFor(_ x: inout sending NonSendableKlass, _ z: NonSendableKlass) -> NonSendableKlass { + for _ in 0..<1 { + if getBool() { + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + } + print(x) + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + + func returnInOutSendingDirectlyFor2(_ x: inout sending NonSendableKlass, _ z: NonSendableKlass) -> NonSendableKlass { + for _ in 0..<1 { + if getBool() { + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + } + print(x) + return z + } + + func returnInOutSendingRegionLetFor(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + let y = x + for _ in 0..<1 { + if getBool() { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + } + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + + func returnInOutSendingRegionLetFor2(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + let y = x + for _ in 0..<1 { + if getBool() { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + } + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + + func returnInOutSendingRegionLetFor3(_ x: inout sending NonSendableKlass, _ z: NonSendableKlass) -> NonSendableKlass { + let y = x + for _ in 0..<1 { + if getBool() { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + } + return z + } + + func returnInOutSendingRegionVarFor(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + var y = x + y = x + for _ in 0..<1 { + if getBool() { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + } + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + + func returnInOutSendingRegionVarFor2(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + var y = x + y = x + for _ in 0..<1 { + if getBool() { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + } + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + + func returnInOutSendingRegionVarFor3(_ x: inout sending NonSendableKlass, _ z: NonSendableKlass) -> NonSendableKlass { + var y = x + y = x + for _ in 0..<1 { + if getBool() { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + } + return z + } + + func returnInOutSendingViaHelperFor(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + let y = x + for _ in 0..<1 { + if getBool() { + return useNonSendableKlassAndReturn(y) // expected-warning {{result of global function 'useNonSendableKlassAndReturn' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + } + print(y) + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + + func returnInOutSendingViaHelperFor2(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + let y = x + for _ in 0..<1 { + if getBool() { + return useNonSendableKlassAndReturn(y) // expected-warning {{result of global function 'useNonSendableKlassAndReturn' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + } + print(y) + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + + func returnInOutSendingHelperDirectFor(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + for _ in 0..<1 { + if getBool() { + return useNonSendableKlassAndReturn(x) // expected-warning {{result of global function 'useNonSendableKlassAndReturn' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + } + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + + func returnInOutSendingViaHelperVarFor(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + var y = x + y = x + for _ in 0..<1 { + if getBool() { + return useNonSendableKlassAndReturn(y) // expected-warning {{result of global function 'useNonSendableKlassAndReturn' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + } + print(y) + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + + func returnInOutSendingDirectlyGuard(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + guard getBool() else { + print(x) + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + + func returnInOutSendingRegionLetGuard(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + let y = x + guard getBool() else { + print(y) + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + + func returnInOutSendingRegionVarGuard(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + var y = x + y = x + guard getBool() else { + print(y) + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + + func returnInOutSendingViaHelperGuard(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + let y = x + guard getBool() else { + print(y) + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + return useNonSendableKlassAndReturn(y) // expected-warning {{result of global function 'useNonSendableKlassAndReturn' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + + func returnInOutSendingHelperDirectGuard(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + guard getBool() else { + print(x) + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + return useNonSendableKlassAndReturn(x) // expected-warning {{result of global function 'useNonSendableKlassAndReturn' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + + func returnInOutSendingViaHelperVarGuard(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + var y = x + y = x + guard getBool() else { + print(y) + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + return useNonSendableKlassAndReturn(y) // expected-warning {{result of global function 'useNonSendableKlassAndReturn' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + + func returnInOutSendingViaHelperVar(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + var y = x + y = x + return useNonSendableKlassAndReturn(y) // expected-warning {{result of global function 'useNonSendableKlassAndReturn' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + + func returnGenericInOutSendingDirectly(_ x: inout sending T) -> T { + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + + func returnGenericInOutSendingRegionLet(_ x: inout sending T) -> T { + let y = x + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + + func returnGenericInOutSendingRegionVar(_ x: inout sending T) -> T { + var y = x + y = x + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + + func returnGenericInOutSendingViaHelper(_ x: inout sending T) -> T { + let y = x + return useValueAndReturnGeneric(y) // expected-warning {{result of global function 'useValueAndReturnGeneric' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useValueAndReturnGeneric' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + + func returnGenericInOutSendingHelperDirect(_ x: inout sending T) -> T { + return useValueAndReturnGeneric(x) // expected-warning {{result of global function 'useValueAndReturnGeneric' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useValueAndReturnGeneric' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + + func returnGenericInOutSendingViaHelperVar(_ x: inout sending T) -> T { + var y = x + y = x + return useValueAndReturnGeneric(y) // expected-warning {{result of global function 'useValueAndReturnGeneric' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useValueAndReturnGeneric' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + + func returnGenericInOutSendingDirectlyIf(_ x: inout sending T) -> T { + if getBool() { + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + fatalError() + } + + func returnGenericInOutSendingRegionLetIf(_ x: inout sending T) -> T { + let y = x + if getBool() { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } else { + print(y) + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + } + + func returnGenericInOutSendingRegionVarIf(_ x: inout sending T) -> T { + var y = x + y = x + if getBool() { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + fatalError() + } + + func returnGenericInOutSendingViaHelperIf(_ x: inout sending T) -> T { + let y = x + if getBool() { + return useValueAndReturnGeneric(y) // expected-warning {{result of global function 'useValueAndReturnGeneric' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useValueAndReturnGeneric' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } else { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + } + + func returnGenericInOutSendingHelperDirectIf(_ x: inout sending T) -> T { + if getBool() { + return useValueAndReturnGeneric(x) // expected-warning {{result of global function 'useValueAndReturnGeneric' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useValueAndReturnGeneric' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } else { + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + } + + func returnGenericInOutSendingViaHelperVarIf(_ x: inout sending T) -> T { + var y = x + y = x + if getBool() { + return useValueAndReturnGeneric(y) // expected-warning {{result of global function 'useValueAndReturnGeneric' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useValueAndReturnGeneric' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } else { + print(y) + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + } + + func returnGenericInOutSendingDirectlyElse(_ x: inout sending T) -> T { + if getBool() { + print(x) + fatalError() + } else { + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + } + + func returnGenericInOutSendingRegionLetElse(_ x: inout sending T) -> T { + let y = x + if getBool() { + print(y) + fatalError() + } else { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + } + + func returnGenericInOutSendingRegionVarElse(_ x: inout sending T, z: T) -> T { + var y = x + y = x + if getBool() { + print(y) + return z + } else { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + } + + func returnGenericInOutSendingViaHelperElse(_ x: inout sending T, _ z: T) -> T { + let y = x + if getBool() { + print(y) + return z + } else { + return useValueAndReturnGeneric(y) // expected-warning {{result of global function 'useValueAndReturnGeneric' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useValueAndReturnGeneric' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + } + + func returnGenericInOutSendingHelperDirectElse(_ x: inout sending T, _ z: T) -> T { + if getBool() { + print(x) + return z + } else { + return useValueAndReturnGeneric(x) // expected-warning {{result of global function 'useValueAndReturnGeneric' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useValueAndReturnGeneric' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + } + + func returnGenericInOutSendingViaHelperVarElse(_ x: inout sending T, _ z: T) -> T { + var y = x + y = x + if getBool() { + print(y) + return z + } else { + return useValueAndReturnGeneric(y) // expected-warning {{result of global function 'useValueAndReturnGeneric' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useValueAndReturnGeneric' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + } + + func returnGenericInOutSendingDirectlyFor(_ x: inout sending T, _ z: T) -> T { + for _ in 0..<1 { + if getBool() { + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + } + print(x) + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + + func returnGenericInOutSendingDirectlyFor2(_ x: inout sending T, _ z: T) -> T { + for _ in 0..<1 { + if getBool() { + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + } + print(x) + return z + } + + func returnGenericInOutSendingRegionLetFor(_ x: inout sending T) -> T { + let y = x + for _ in 0..<1 { + if getBool() { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + } + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + + func returnGenericInOutSendingRegionLetFor2(_ x: inout sending T) -> T { + let y = x + for _ in 0..<1 { + if getBool() { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + } + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + + func returnGenericInOutSendingRegionLetFor3(_ x: inout sending T, _ z: T) -> T { + let y = x + for _ in 0..<1 { + if getBool() { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + } + return z + } + + func returnGenericInOutSendingRegionVarFor(_ x: inout sending T) -> T { + var y = x + y = x + for _ in 0..<1 { + if getBool() { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + } + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + + func returnGenericInOutSendingRegionVarFor2(_ x: inout sending T) -> T { + var y = x + y = x + for _ in 0..<1 { + if getBool() { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + } + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + + func returnGenericInOutSendingRegionVarFor3(_ x: inout sending T, _ z: T) -> T { + var y = x + y = x + for _ in 0..<1 { + if getBool() { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + } + return z + } + + func returnGenericInOutSendingViaHelperFor(_ x: inout sending T) -> T { + let y = x + for _ in 0..<1 { + if getBool() { + return useValueAndReturnGeneric(y) // expected-warning {{result of global function 'useValueAndReturnGeneric' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useValueAndReturnGeneric' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + } + print(y) + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + + func returnGenericInOutSendingViaHelperFor2(_ x: inout sending T) -> T { + let y = x + for _ in 0..<1 { + if getBool() { + return useValueAndReturnGeneric(y) // expected-warning {{result of global function 'useValueAndReturnGeneric' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useValueAndReturnGeneric' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + } + print(y) + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + + func returnGenericInOutSendingHelperDirectFor(_ x: inout sending T) -> T { + for _ in 0..<1 { + if getBool() { + return useValueAndReturnGeneric(x) // expected-warning {{result of global function 'useValueAndReturnGeneric' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useValueAndReturnGeneric' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + } + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + + func returnGenericInOutSendingViaHelperVarFor(_ x: inout sending T) -> T { + var y = x + y = x + for _ in 0..<1 { + if getBool() { + return useValueAndReturnGeneric(y) // expected-warning {{result of global function 'useValueAndReturnGeneric' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useValueAndReturnGeneric' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + } + print(y) + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + + func returnGenericInOutSendingDirectlyGuard(_ x: inout sending T) -> T { + guard getBool() else { + print(x) + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + + func returnGenericInOutSendingRegionLetGuard(_ x: inout sending T) -> T { + let y = x + guard getBool() else { + print(y) + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + + func returnGenericInOutSendingRegionVarGuard(_ x: inout sending T) -> T { + var y = x + y = x + guard getBool() else { + print(y) + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + + func returnGenericInOutSendingViaHelperGuard(_ x: inout sending T) -> T { + let y = x + guard getBool() else { + print(y) + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + return useValueAndReturnGeneric(y) // expected-warning {{result of global function 'useValueAndReturnGeneric' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useValueAndReturnGeneric' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + + func returnGenericInOutSendingHelperDirectGuard(_ x: inout sending T) -> T { + guard getBool() else { + print(x) + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + return useValueAndReturnGeneric(x) // expected-warning {{result of global function 'useValueAndReturnGeneric' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useValueAndReturnGeneric' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + + func returnGenericInOutSendingViaHelperVarGuard(_ x: inout sending T) -> T { + var y = x + y = x + guard getBool() else { + print(y) + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } + return useValueAndReturnGeneric(y) // expected-warning {{result of global function 'useValueAndReturnGeneric' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useValueAndReturnGeneric' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is 'self'-isolated}} + } +} + +//////////////////////////////////////////////////////////////// +// MARK: ReturnSendingInOutTestGlobalActorIsolatedClass Tests // +//////////////////////////////////////////////////////////////// + +@MainActor +class ReturnSendingInOutTestGlobalActorIsolatedClass { + + func testInOutSendingReinit(_ x: inout sending NonSendableKlass) async { + await transferToCustom(x) // expected-warning {{sending 'x' risks causing data races}} + } // expected-note {{'inout sending' parameter must be reinitialized before function exit with a non-actor-isolated value}} + // expected-note @-2 {{sending 'x' to global actor 'CustomActor'-isolated global function 'transferToCustom' risks causing data races between global actor 'CustomActor'-isolated and local main actor-isolated uses}} + + func testInOutSendingReinit2(_ x: inout sending NonSendableKlass) async { + await transferToCustom(x) + x = NonSendableKlass() + } + + func testInOutSendingReinit3(_ x: inout sending NonSendableKlass) async throws { + await transferToCustom(x) // expected-warning {{sending 'x' risks causing data races}} + // expected-note @-1 {{sending 'x' to global actor 'CustomActor'-isolated global function 'transferToCustom' risks causing data races between global actor 'CustomActor'-isolated and local main actor-isolated uses}} + + try throwingFunction() // expected-note {{'inout sending' parameter must be reinitialized before function exit with a non-actor-isolated value}} + + x = NonSendableKlass() + } + + func testInOutSendingReinit4(_ x: inout sending NonSendableKlass) async throws { + await transferToCustom(x) // expected-warning {{sending 'x' risks causing data races}} + // expected-note @-1 {{sending 'x' to global actor 'CustomActor'-isolated global function 'transferToCustom' risks causing data races between global actor 'CustomActor'-isolated and local main actor-isolated uses}} + + do { + try throwingFunction() + x = NonSendableKlass() + } catch { + throw MyError() // expected-note {{'inout sending' parameter must be reinitialized before function exit with a non-actor-isolated value}} + } + + x = NonSendableKlass() + } + + func testInOutSendingReinit5(_ x: inout sending NonSendableKlass) async throws { + await transferToCustom(x) // expected-warning {{sending 'x' risks causing data races}} + // expected-note @-1 {{sending 'x' to global actor 'CustomActor'-isolated global function 'transferToCustom' risks causing data races between global actor 'CustomActor'-isolated and local main actor-isolated uses}} + + do { + try throwingFunction() + } catch { + throw MyError() // expected-note {{'inout sending' parameter must be reinitialized before function exit with a non-actor-isolated value}} + } + + x = NonSendableKlass() + } + + func testInOutSendingReinit6(_ x: inout sending NonSendableKlass) async throws { + await transferToCustom(x) // expected-warning {{sending 'x' risks causing data races}} + // expected-note @-1 {{sending 'x' to global actor 'CustomActor'-isolated global function 'transferToCustom' risks causing data races between global actor 'CustomActor'-isolated and local main actor-isolated uses}} + + do { + try throwingFunction() + } catch { + throw MyError() // expected-note {{'inout sending' parameter must be reinitialized before function exit with a non-actor-isolated value}} + } + } // expected-note {{'inout sending' parameter must be reinitialized before function exit with a non-actor-isolated value}} + + func returnInOutSendingDirectly(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + + func returnInOutSendingRegionLet(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + let y = x + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + + func returnInOutSendingRegionVar(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + var y = x + y = x + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + + func returnInOutSendingViaHelper(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + let y = x + return useNonSendableKlassAndReturn(y) // expected-warning {{result of global function 'useNonSendableKlassAndReturn' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + + func returnInOutSendingHelperDirect(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + return useNonSendableKlassAndReturn(x) // expected-warning {{result of global function 'useNonSendableKlassAndReturn' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + + func returnInOutSendingDirectlyIf(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + if getBool() { + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + fatalError() + } + + func returnInOutSendingRegionLetIf(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + let y = x + if getBool() { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } else { + print(y) + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + } + + func returnInOutSendingRegionVarIf(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + var y = x + y = x + if getBool() { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + fatalError() + } + + func returnInOutSendingViaHelperIf(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + let y = x + if getBool() { + return useNonSendableKlassAndReturn(y) // expected-warning {{result of global function 'useNonSendableKlassAndReturn' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } else { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + } + + func returnInOutSendingHelperDirectIf(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + if getBool() { + return useNonSendableKlassAndReturn(x) // expected-warning {{result of global function 'useNonSendableKlassAndReturn' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } else { + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + } + + func returnInOutSendingViaHelperVarIf(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + var y = x + y = x + if getBool() { + return useNonSendableKlassAndReturn(y) // expected-warning {{result of global function 'useNonSendableKlassAndReturn' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } else { + print(y) + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + } + + func returnInOutSendingDirectlyElse(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + if getBool() { + print(x) + fatalError() + } else { + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + } + + func returnInOutSendingRegionLetElse(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + let y = x + if getBool() { + print(y) + fatalError() + } else { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + } + + func returnInOutSendingRegionVarElse(_ x: inout sending NonSendableKlass, z: NonSendableKlass) -> NonSendableKlass { + var y = x + y = x + if getBool() { + print(y) + return z + } else { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + } + + func returnInOutSendingViaHelperElse(_ x: inout sending NonSendableKlass, _ z: NonSendableKlass) -> NonSendableKlass { + let y = x + if getBool() { + print(y) + return z + } else { + return useNonSendableKlassAndReturn(y) // expected-warning {{result of global function 'useNonSendableKlassAndReturn' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + } + + func returnInOutSendingHelperDirectElse(_ x: inout sending NonSendableKlass, _ z: NonSendableKlass) -> NonSendableKlass { + if getBool() { + print(x) + return z + } else { + return useNonSendableKlassAndReturn(x) // expected-warning {{result of global function 'useNonSendableKlassAndReturn' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + } + + func returnInOutSendingViaHelperVarElse(_ x: inout sending NonSendableKlass, _ z: NonSendableKlass) -> NonSendableKlass { + var y = x + y = x + if getBool() { + print(y) + return z + } else { + return useNonSendableKlassAndReturn(y) // expected-warning {{result of global function 'useNonSendableKlassAndReturn' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + } + + func returnInOutSendingDirectlyFor(_ x: inout sending NonSendableKlass, _ z: NonSendableKlass) -> NonSendableKlass { + for _ in 0..<1 { + if getBool() { + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + } + print(x) + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + + func returnInOutSendingDirectlyFor2(_ x: inout sending NonSendableKlass, _ z: NonSendableKlass) -> NonSendableKlass { + for _ in 0..<1 { + if getBool() { + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + } + print(x) + return z + } + + func returnInOutSendingRegionLetFor(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + let y = x + for _ in 0..<1 { + if getBool() { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + } + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + + func returnInOutSendingRegionLetFor2(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + let y = x + for _ in 0..<1 { + if getBool() { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + } + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + + func returnInOutSendingRegionLetFor3(_ x: inout sending NonSendableKlass, _ z: NonSendableKlass) -> NonSendableKlass { + let y = x + for _ in 0..<1 { + if getBool() { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + } + return z + } + + func returnInOutSendingRegionVarFor(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + var y = x + y = x + for _ in 0..<1 { + if getBool() { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + } + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + + func returnInOutSendingRegionVarFor2(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + var y = x + y = x + for _ in 0..<1 { + if getBool() { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + } + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + + func returnInOutSendingRegionVarFor3(_ x: inout sending NonSendableKlass, _ z: NonSendableKlass) -> NonSendableKlass { + var y = x + y = x + for _ in 0..<1 { + if getBool() { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + } + return z + } + + func returnInOutSendingViaHelperFor(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + let y = x + for _ in 0..<1 { + if getBool() { + return useNonSendableKlassAndReturn(y) // expected-warning {{result of global function 'useNonSendableKlassAndReturn' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + } + print(y) + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + + func returnInOutSendingViaHelperFor2(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + let y = x + for _ in 0..<1 { + if getBool() { + return useNonSendableKlassAndReturn(y) // expected-warning {{result of global function 'useNonSendableKlassAndReturn' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + } + print(y) + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + + func returnInOutSendingHelperDirectFor(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + for _ in 0..<1 { + if getBool() { + return useNonSendableKlassAndReturn(x) // expected-warning {{result of global function 'useNonSendableKlassAndReturn' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + } + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + + func returnInOutSendingViaHelperVarFor(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + var y = x + y = x + for _ in 0..<1 { + if getBool() { + return useNonSendableKlassAndReturn(y) // expected-warning {{result of global function 'useNonSendableKlassAndReturn' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + } + print(y) + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + + func returnInOutSendingDirectlyGuard(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + guard getBool() else { + print(x) + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + + func returnInOutSendingRegionLetGuard(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + let y = x + guard getBool() else { + print(y) + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + + func returnInOutSendingRegionVarGuard(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + var y = x + y = x + guard getBool() else { + print(y) + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + + func returnInOutSendingViaHelperGuard(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + let y = x + guard getBool() else { + print(y) + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + return useNonSendableKlassAndReturn(y) // expected-warning {{result of global function 'useNonSendableKlassAndReturn' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + + func returnInOutSendingHelperDirectGuard(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + guard getBool() else { + print(x) + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + return useNonSendableKlassAndReturn(x) // expected-warning {{result of global function 'useNonSendableKlassAndReturn' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + + func returnInOutSendingViaHelperVarGuard(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + var y = x + y = x + guard getBool() else { + print(y) + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + return useNonSendableKlassAndReturn(y) // expected-warning {{result of global function 'useNonSendableKlassAndReturn' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + + func returnInOutSendingViaHelperVar(_ x: inout sending NonSendableKlass) -> NonSendableKlass { + var y = x + y = x + return useNonSendableKlassAndReturn(y) // expected-warning {{result of global function 'useNonSendableKlassAndReturn' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + + func returnGenericInOutSendingDirectly(_ x: inout sending T) -> T { + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + + func returnGenericInOutSendingRegionLet(_ x: inout sending T) -> T { + let y = x + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + + func returnGenericInOutSendingRegionVar(_ x: inout sending T) -> T { + var y = x + y = x + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + + func returnGenericInOutSendingViaHelper(_ x: inout sending T) -> T { + let y = x + return useValueAndReturnGeneric(y) // expected-warning {{result of global function 'useValueAndReturnGeneric' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useValueAndReturnGeneric' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + + func returnGenericInOutSendingHelperDirect(_ x: inout sending T) -> T { + return useValueAndReturnGeneric(x) // expected-warning {{result of global function 'useValueAndReturnGeneric' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useValueAndReturnGeneric' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + + func returnGenericInOutSendingViaHelperVar(_ x: inout sending T) -> T { + var y = x + y = x + return useValueAndReturnGeneric(y) // expected-warning {{result of global function 'useValueAndReturnGeneric' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useValueAndReturnGeneric' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + + func returnGenericInOutSendingDirectlyIf(_ x: inout sending T) -> T { + if getBool() { + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + fatalError() + } + + func returnGenericInOutSendingRegionLetIf(_ x: inout sending T) -> T { + let y = x + if getBool() { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } else { + print(y) + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + } + + func returnGenericInOutSendingRegionVarIf(_ x: inout sending T) -> T { + var y = x + y = x + if getBool() { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + fatalError() + } + + func returnGenericInOutSendingViaHelperIf(_ x: inout sending T) -> T { + let y = x + if getBool() { + return useValueAndReturnGeneric(y) // expected-warning {{result of global function 'useValueAndReturnGeneric' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useValueAndReturnGeneric' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } else { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + } + + func returnGenericInOutSendingHelperDirectIf(_ x: inout sending T) -> T { + if getBool() { + return useValueAndReturnGeneric(x) // expected-warning {{result of global function 'useValueAndReturnGeneric' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useValueAndReturnGeneric' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } else { + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + } + + func returnGenericInOutSendingViaHelperVarIf(_ x: inout sending T) -> T { + var y = x + y = x + if getBool() { + return useValueAndReturnGeneric(y) // expected-warning {{result of global function 'useValueAndReturnGeneric' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useValueAndReturnGeneric' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } else { + print(y) + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + } + + func returnGenericInOutSendingDirectlyElse(_ x: inout sending T) -> T { + if getBool() { + print(x) + fatalError() + } else { + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + } + + func returnGenericInOutSendingRegionLetElse(_ x: inout sending T) -> T { + let y = x + if getBool() { + print(y) + fatalError() + } else { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + } + + func returnGenericInOutSendingRegionVarElse(_ x: inout sending T, z: T) -> T { + var y = x + y = x + if getBool() { + print(y) + return z + } else { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + } + + func returnGenericInOutSendingViaHelperElse(_ x: inout sending T, _ z: T) -> T { + let y = x + if getBool() { + print(y) + return z + } else { + return useValueAndReturnGeneric(y) // expected-warning {{result of global function 'useValueAndReturnGeneric' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useValueAndReturnGeneric' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + } + + func returnGenericInOutSendingHelperDirectElse(_ x: inout sending T, _ z: T) -> T { + if getBool() { + print(x) + return z + } else { + return useValueAndReturnGeneric(x) // expected-warning {{result of global function 'useValueAndReturnGeneric' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useValueAndReturnGeneric' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + } + + func returnGenericInOutSendingViaHelperVarElse(_ x: inout sending T, _ z: T) -> T { + var y = x + y = x + if getBool() { + print(y) + return z + } else { + return useValueAndReturnGeneric(y) // expected-warning {{result of global function 'useValueAndReturnGeneric' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useValueAndReturnGeneric' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + } + + func returnGenericInOutSendingDirectlyFor(_ x: inout sending T, _ z: T) -> T { + for _ in 0..<1 { + if getBool() { + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + } + print(x) + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + + func returnGenericInOutSendingDirectlyFor2(_ x: inout sending T, _ z: T) -> T { + for _ in 0..<1 { + if getBool() { + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + } + print(x) + return z + } + + func returnGenericInOutSendingRegionLetFor(_ x: inout sending T) -> T { + let y = x + for _ in 0..<1 { + if getBool() { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + } + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + + func returnGenericInOutSendingRegionLetFor2(_ x: inout sending T) -> T { + let y = x + for _ in 0..<1 { + if getBool() { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + } + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + + func returnGenericInOutSendingRegionLetFor3(_ x: inout sending T, _ z: T) -> T { + let y = x + for _ in 0..<1 { + if getBool() { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + } + return z + } + + func returnGenericInOutSendingRegionVarFor(_ x: inout sending T) -> T { + var y = x + y = x + for _ in 0..<1 { + if getBool() { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + } + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + + func returnGenericInOutSendingRegionVarFor2(_ x: inout sending T) -> T { + var y = x + y = x + for _ in 0..<1 { + if getBool() { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + } + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + + func returnGenericInOutSendingRegionVarFor3(_ x: inout sending T, _ z: T) -> T { + var y = x + y = x + for _ in 0..<1 { + if getBool() { + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + } + return z + } + + func returnGenericInOutSendingViaHelperFor(_ x: inout sending T) -> T { + let y = x + for _ in 0..<1 { + if getBool() { + return useValueAndReturnGeneric(y) // expected-warning {{result of global function 'useValueAndReturnGeneric' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useValueAndReturnGeneric' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + } + print(y) + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + + func returnGenericInOutSendingViaHelperFor2(_ x: inout sending T) -> T { + let y = x + for _ in 0..<1 { + if getBool() { + return useValueAndReturnGeneric(y) // expected-warning {{result of global function 'useValueAndReturnGeneric' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useValueAndReturnGeneric' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + } + print(y) + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + + func returnGenericInOutSendingHelperDirectFor(_ x: inout sending T) -> T { + for _ in 0..<1 { + if getBool() { + return useValueAndReturnGeneric(x) // expected-warning {{result of global function 'useValueAndReturnGeneric' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useValueAndReturnGeneric' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + } + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + + func returnGenericInOutSendingViaHelperVarFor(_ x: inout sending T) -> T { + var y = x + y = x + for _ in 0..<1 { + if getBool() { + return useValueAndReturnGeneric(y) // expected-warning {{result of global function 'useValueAndReturnGeneric' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useValueAndReturnGeneric' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + } + print(y) + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + + func returnGenericInOutSendingDirectlyGuard(_ x: inout sending T) -> T { + guard getBool() else { + print(x) + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + + func returnGenericInOutSendingRegionLetGuard(_ x: inout sending T) -> T { + let y = x + guard getBool() else { + print(y) + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + + func returnGenericInOutSendingRegionVarGuard(_ x: inout sending T) -> T { + var y = x + y = x + guard getBool() else { + print(y) + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + + func returnGenericInOutSendingViaHelperGuard(_ x: inout sending T) -> T { + let y = x + guard getBool() else { + print(y) + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + return useValueAndReturnGeneric(y) // expected-warning {{result of global function 'useValueAndReturnGeneric' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useValueAndReturnGeneric' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + + func returnGenericInOutSendingHelperDirectGuard(_ x: inout sending T) -> T { + guard getBool() else { + print(x) + return x // expected-warning {{'inout sending' parameter 'x' cannot be returned}} + // expected-note @-1 {{returning 'x' risks concurrent access as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + return useValueAndReturnGeneric(x) // expected-warning {{result of global function 'useValueAndReturnGeneric' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useValueAndReturnGeneric' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + + func returnGenericInOutSendingViaHelperVarGuard(_ x: inout sending T) -> T { + var y = x + y = x + guard getBool() else { + print(y) + return y // expected-warning {{'y' cannot be returned}} + // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } + return useValueAndReturnGeneric(y) // expected-warning {{result of global function 'useValueAndReturnGeneric' cannot be returned}} + // expected-note @-1 {{returning result of global function 'useValueAndReturnGeneric' risks concurrent access to 'inout sending' parameter 'x' as caller assumes 'x' is not actor-isolated and result is main actor-isolated}} + } +} + +////////////////////// +// MARK: Misc Tests // +////////////////////// + func taskIsolatedCaptureInSendingClosureLiteral(_ x: NonSendableKlass) { Task { // expected-warning {{passing closure as a 'sending' parameter risks causing data races between code in the current task and concurrent execution of the closure}} print(x) // expected-note {{closure captures 'x' which is accessible to code in the current task}} diff --git a/unittests/SILOptimizer/PartitionUtilsTest.cpp b/unittests/SILOptimizer/PartitionUtilsTest.cpp index 9247017ef66d7..d86163bc5f9e2 100644 --- a/unittests/SILOptimizer/PartitionUtilsTest.cpp +++ b/unittests/SILOptimizer/PartitionUtilsTest.cpp @@ -98,6 +98,7 @@ struct MockedPartitionOpEvaluatorWithFailureCallback final case PartitionOpError::InOutSendingNotInitializedAtExit: case PartitionOpError::InOutSendingNotDisconnectedAtExit: case PartitionOpError::NonSendableIsolationCrossingResult: + case PartitionOpError::InOutSendingReturned: llvm_unreachable("Unsupported"); case PartitionOpError::LocalUseAfterSend: { auto state = error.getLocalUseAfterSendError();