@@ -723,6 +723,7 @@ struct DiagnosticEvaluator final
723723 case PartitionOpError::SentNeverSendable:
724724 case PartitionOpError::AssignNeverSendableIntoSendingResult:
725725 case PartitionOpError::NonSendableIsolationCrossingResult:
726+ case PartitionOpError::InOutSendingParametersInSameRegion:
726727 // We are going to process these later... but dump so we can see that we
727728 // handled an error here. The rest of the explicit handlers will dump as
728729 // appropriate if they want to emit an error here (some will squelch the
@@ -3501,6 +3502,138 @@ void NonSendableIsolationCrossingResultDiagnosticEmitter::emit() {
35013502 }
35023503}
35033504
3505+ // ===----------------------------------------------------------------------===//
3506+ // MARK: InOutSendingParametersInSameRegionError
3507+ // ===----------------------------------------------------------------------===//
3508+
3509+ namespace {
3510+
3511+ class InOutSendingParametersInSameRegionDiagnosticEmitter {
3512+ // / The function exiting inst where the 'inout sending' parameter was actor
3513+ // / isolated.
3514+ TermInst *functionExitingInst;
3515+
3516+ // / The first 'inout sending' param in the region.
3517+ SILValue firstInOutSendingParam;
3518+
3519+ // / The second 'inout sending' param in the region.
3520+ SILValue secondInOutSendingParam;
3521+
3522+ bool emittedErrorDiagnostic = false ;
3523+
3524+ public:
3525+ InOutSendingParametersInSameRegionDiagnosticEmitter (
3526+ TermInst *functionExitingInst, SILValue firstInOutSendingParam,
3527+ SILValue secondInOutSendingParam)
3528+ : functionExitingInst(functionExitingInst),
3529+ firstInOutSendingParam (firstInOutSendingParam),
3530+ secondInOutSendingParam(secondInOutSendingParam) {}
3531+
3532+ ~InOutSendingParametersInSameRegionDiagnosticEmitter () {
3533+ // If we were supposed to emit a diagnostic and didn't emit an unknown
3534+ // pattern error.
3535+ if (!emittedErrorDiagnostic)
3536+ emitUnknownPatternError ();
3537+ }
3538+
3539+ SILFunction *getFunction () const {
3540+ return functionExitingInst->getFunction ();
3541+ }
3542+
3543+ std::optional<DiagnosticBehavior> getBehaviorLimit () const {
3544+ auto first =
3545+ firstInOutSendingParam->getType ().getConcurrencyDiagnosticBehavior (
3546+ getFunction ());
3547+ auto second =
3548+ secondInOutSendingParam->getType ().getConcurrencyDiagnosticBehavior (
3549+ getFunction ());
3550+ if (!first)
3551+ return second;
3552+ if (!second)
3553+ return first;
3554+ return first->merge (*second);
3555+ }
3556+
3557+ void emitUnknownPatternError () {
3558+ if (shouldAbortOnUnknownPatternMatchError ()) {
3559+ llvm::report_fatal_error (
3560+ " RegionIsolation: Aborting on unknown pattern match error" );
3561+ }
3562+
3563+ diagnoseError (functionExitingInst,
3564+ diag::regionbasedisolation_unknown_pattern)
3565+ .limitBehaviorIf (getBehaviorLimit ());
3566+ }
3567+
3568+ void emit ();
3569+
3570+ ASTContext &getASTContext () const {
3571+ return functionExitingInst->getFunction ()->getASTContext ();
3572+ }
3573+
3574+ template <typename ... T, typename ... U>
3575+ InFlightDiagnostic diagnoseError (SourceLoc loc, Diag<T...> diag,
3576+ U &&...args) {
3577+ emittedErrorDiagnostic = true ;
3578+ return std::move (getASTContext ()
3579+ .Diags .diagnose (loc, diag, std::forward<U>(args)...)
3580+ .warnUntilSwiftVersion (6 ));
3581+ }
3582+
3583+ template <typename ... T, typename ... U>
3584+ InFlightDiagnostic diagnoseError (SILLocation loc, Diag<T...> diag,
3585+ U &&...args) {
3586+ return diagnoseError (loc.getSourceLoc (), diag, std::forward<U>(args)...);
3587+ }
3588+
3589+ template <typename ... T, typename ... U>
3590+ InFlightDiagnostic diagnoseError (SILInstruction *inst, Diag<T...> diag,
3591+ U &&...args) {
3592+ return diagnoseError (inst->getLoc (), diag, std::forward<U>(args)...);
3593+ }
3594+
3595+ template <typename ... T, typename ... U>
3596+ InFlightDiagnostic diagnoseNote (SourceLoc loc, Diag<T...> diag, U &&...args) {
3597+ return getASTContext ().Diags .diagnose (loc, diag, std::forward<U>(args)...);
3598+ }
3599+
3600+ template <typename ... T, typename ... U>
3601+ InFlightDiagnostic diagnoseNote (SILLocation loc, Diag<T...> diag,
3602+ U &&...args) {
3603+ return diagnoseNote (loc.getSourceLoc (), diag, std::forward<U>(args)...);
3604+ }
3605+
3606+ template <typename ... T, typename ... U>
3607+ InFlightDiagnostic diagnoseNote (SILInstruction *inst, Diag<T...> diag,
3608+ U &&...args) {
3609+ return diagnoseNote (inst->getLoc (), diag, std::forward<U>(args)...);
3610+ }
3611+ };
3612+
3613+ } // namespace
3614+
3615+ void InOutSendingParametersInSameRegionDiagnosticEmitter::emit () {
3616+ // We should always be able to find a name for an inout sending param. If we
3617+ // do not, emit an unknown pattern error.
3618+ auto firstName = inferNameHelper (firstInOutSendingParam);
3619+ if (!firstName) {
3620+ return emitUnknownPatternError ();
3621+ }
3622+ auto secondName = inferNameHelper (secondInOutSendingParam);
3623+ if (!secondName) {
3624+ return emitUnknownPatternError ();
3625+ }
3626+
3627+ diagnoseError (functionExitingInst,
3628+ diag::regionbasedisolation_inout_sending_in_same_region,
3629+ *firstName, *secondName)
3630+ .limitBehaviorIf (getBehaviorLimit ());
3631+
3632+ diagnoseNote (functionExitingInst,
3633+ diag::regionbasedisolation_inout_sending_in_same_region_note,
3634+ *firstName, *secondName);
3635+ }
3636+
35043637// ===----------------------------------------------------------------------===//
35053638// MARK: Top Level Entrypoint
35063639// ===----------------------------------------------------------------------===//
@@ -3569,6 +3702,30 @@ void SendNonSendableImpl::emitVerbatimErrors() {
35693702 diagnosticInferrer.emit ();
35703703 continue ;
35713704 }
3705+ case PartitionOpError::InOutSendingParametersInSameRegion: {
3706+ auto e =
3707+ std::move (erasedError).getInOutSendingParametersInSameRegionError ();
3708+ REGIONBASEDISOLATION_LOG (e.print (llvm::dbgs (), info->getValueMap ()));
3709+ auto firstParam =
3710+ info->getValueMap ().getRepresentativeValue (e.firstInoutSendingParam );
3711+ // Walk through our secondInOutSendingParams and use one that is not
3712+ // ignore.
3713+ for (auto paramElt : e.otherInOutSendingParams ) {
3714+ auto paramValue =
3715+ info->getValueMap ().getRepresentativeValue (paramElt).getValue ();
3716+ if (auto behavior =
3717+ paramValue->getType ().getConcurrencyDiagnosticBehavior (
3718+ info->getFunction ());
3719+ behavior && *behavior == DiagnosticBehavior::Ignore) {
3720+ continue ;
3721+ }
3722+ InOutSendingParametersInSameRegionDiagnosticEmitter diagnosticEmitter (
3723+ cast<TermInst>(e.op ->getSourceInst ()), firstParam.getValue (),
3724+ paramValue);
3725+ diagnosticEmitter.emit ();
3726+ }
3727+ continue ;
3728+ }
35723729 }
35733730 llvm_unreachable (" Covered switch isn't covered?!" );
35743731 }
0 commit comments