diff --git a/include/swift/AST/DiagnosticsSIL.def b/include/swift/AST/DiagnosticsSIL.def index 4e5e1633db597..943e67e29be8f 100644 --- a/include/swift/AST/DiagnosticsSIL.def +++ b/include/swift/AST/DiagnosticsSIL.def @@ -315,12 +315,12 @@ ERROR(missing_never_call_closure,none, (Type)) ERROR(missing_return_decl,none, - "missing return in %1 expected to return %0", - (Type, DescriptiveDeclKind)) + "missing return in %kindonly1 expected to return %0", + (Type, const AbstractFunctionDecl *)) ERROR(missing_never_call_decl,none, - "%1 with uninhabited return type %0 is missing " + "%kindonly1 with uninhabited return type %0 is missing " "call to another never-returning function on all paths", - (Type, DescriptiveDeclKind)) + (Type, const AbstractFunctionDecl *)) NOTE(missing_return_last_expr_note,none, "did you mean to return the last expression?", ()) @@ -701,8 +701,9 @@ WARNING(warning_int_to_fp_inexact, none, // Flow-isolation diagnostics ERROR(isolated_after_nonisolated, none, - "cannot access %1 %2 here in %select{nonisolated initializer|deinitializer}0", - (bool, DescriptiveDeclKind, DeclName)) + "cannot access %kind1 here in " + "%select{nonisolated initializer|deinitializer}0", + (bool, const ValueDecl *)) NOTE(nonisolated_blame, none, "after %1%2 %3, " "only nonisolated properties of 'self' can be accessed from " "%select{this init|a deinit}0", (bool, StringRef, StringRef, DeclName)) @@ -982,23 +983,23 @@ GROUPED_ERROR(regionbasedisolation_type_send_yields_race, SendingRisksDataRace, (Type)) NOTE(regionbasedisolation_type_use_after_send, none, "sending value of non-Sendable type %0 to %1 callee risks causing data races between %1 and local %2 uses", - (Type, ActorIsolation, ActorIsolation)) + (Type, StringRef, StringRef)) NOTE(regionbasedisolation_type_use_after_send_callee, none, - "sending value of non-Sendable type %0 to %1 %2 %3 risks causing data " - "races between %1 and local %4 uses", - (Type, ActorIsolation, DescriptiveDeclKind, DeclName, ActorIsolation)) + "sending value of non-Sendable type %0 to %1 %kind2 risks causing data " + "races between %1 and local %3 uses", + (Type, StringRef, const ValueDecl *, StringRef)) NOTE(regionbasedisolation_named_info_send_yields_race, none, - "sending %1%0 to %2 callee risks causing data races between %2 and local %3 uses", - (Identifier, StringRef, ActorIsolation, ActorIsolation)) + "sending %select{%2 |}0%1 to %3 callee risks causing data races between %3 and local %4 uses", + (bool, Identifier, StringRef, StringRef, StringRef)) NOTE(regionbasedisolation_named_info_send_yields_race_callee, none, - "sending %1%0 to %2 %3 %4 risks causing data races between %2 and local %5 uses", - (Identifier, StringRef, ActorIsolation, DescriptiveDeclKind, DeclName, ActorIsolation)) + "sending %select{%2 |}0%1 to %3 %kind4 risks causing data races between %3 and local %5 uses", + (bool, Identifier, StringRef, StringRef, const ValueDecl *, StringRef)) // Use after send closure. NOTE(regionbasedisolation_type_isolated_capture_yields_race, none, "sending value of non-Sendable type %0 to %1 closure due to closure capture risks causing races in between %1 and %2 uses", - (Type, ActorIsolation, ActorIsolation)) + (Type, StringRef, StringRef)) // Value captured in async let and reused. NOTE(regionbasedisolation_named_nonisolated_asynclet_name, none, @@ -1009,33 +1010,33 @@ NOTE(regionbasedisolation_named_value_used_after_explicit_sending, none, "%0 used after being passed as a 'sending' parameter; Later uses could race", (Identifier)) NOTE(regionbasedisolation_named_isolated_closure_yields_race, none, - "%0%1 is captured by a %2 closure. %2 uses in closure may race against later %3 uses", - (StringRef, Identifier, ActorIsolation, ActorIsolation)) + "%select{%1 |}0%2 is captured by a %3 closure. %3 uses in closure may race against later %4 uses", + (bool, StringRef, Identifier, StringRef, StringRef)) NOTE(regionbasedisolation_typed_use_after_sending, none, "Passing value of non-Sendable type %0 as a 'sending' argument risks causing races in between local and caller code", (Type)) NOTE(regionbasedisolation_typed_use_after_sending_callee, none, - "Passing value of non-Sendable type %0 as a 'sending' argument to %1 %2 risks causing races in between local and caller code", - (Type, DescriptiveDeclKind, DeclName)) + "Passing value of non-Sendable type %0 as a 'sending' argument to %kind1 risks causing races in between local and caller code", + (Type, const ValueDecl *)) //=== // Sending Never Sendable Emitter NOTE(regionbasedisolation_named_send_never_sendable, none, - "sending %1%0 to %2 callee risks causing data races between %2 and %3 uses", - (Identifier, StringRef, ActorIsolation, StringRef)) + "sending %select{%2 |}0%1 to %3 callee risks causing data races between %3 and %4 uses", + (bool, Identifier, StringRef, StringRef, StringRef)) NOTE(regionbasedisolation_named_send_never_sendable_callee, none, - "sending %1%0 to %2 %3 %4 risks causing data races between %2 and %5 uses", - (Identifier, StringRef, ActorIsolation, DescriptiveDeclKind, DeclName, StringRef)) + "sending %select{%2 |}0%1 to %3 %kind4 risks causing data races between %3 and %5 uses", + (bool, Identifier, StringRef, StringRef, const ValueDecl *, StringRef)) NOTE(regionbasedisolation_named_send_into_sending_param, none, - "%0%1 is passed as a 'sending' parameter; Uses in callee may race with " - "later %0uses", - (StringRef, Identifier)) + "%select{%1 |}0%2 is passed as a 'sending' parameter; Uses in callee may race with " + "later %1 uses", + (bool, StringRef, Identifier)) NOTE(regionbasedisolation_named_nosend_send_into_result, none, - "%0%1 cannot be a 'sending' result. %2 uses may race with caller uses", - (StringRef, Identifier, StringRef)) + "%select{%1 |}0%2 cannot be a 'sending' result. %3 uses may race with caller uses", + (bool, StringRef, Identifier, StringRef)) NOTE(regionbasedisolation_typed_tns_passed_to_sending, none, "Passing %0 value of non-Sendable type %1 as a 'sending' parameter risks " "causing races inbetween %0 uses and uses reachable from the callee", @@ -1051,8 +1052,8 @@ NOTE(regionbasedisolation_typed_tns_passed_to_sending_closure_helper_have_value_ "closure captures %0 which is accessible to code in the current task", (DeclName)) NOTE(regionbasedisolation_typed_tns_passed_to_sending_closure_helper_have_boxed_value_task_isolated, none, - "closure captures reference to mutable %1 %0 which is accessible to code in the current task", - (DeclName, DescriptiveDeclKind)) + "closure captures reference to mutable %kind0 which is accessible to code in the current task", + (const ValueDecl *)) NOTE(regionbasedisolation_typed_tns_passed_to_sending_closure_helper_have_value_region, none, "closure captures %1 which is accessible to %0 code", (StringRef, DeclName)) @@ -1068,18 +1069,18 @@ NOTE(regionbasedisolation_closure_captures_actor, none, (DeclName, StringRef)) NOTE(regionbasedisolation_typed_tns_passed_to_sending_callee, none, - "Passing %0 value of non-Sendable type %1 as a 'sending' parameter to %2 %3 risks causing races inbetween %0 uses and uses reachable from %3", - (StringRef, Type, DescriptiveDeclKind, DeclName)) + "Passing %0 value of non-Sendable type %1 as a 'sending' parameter to %kind2 risks causing races inbetween %0 uses and uses reachable from %2", + (StringRef, Type, const ValueDecl *)) NOTE(regionbasedisolation_named_send_nt_asynclet_capture, none, "sending %1 %0 into async let risks causing data races between nonisolated and %1 uses", (Identifier, StringRef)) NOTE(regionbasedisolation_typed_sendneversendable_via_arg, none, "sending %0 value of non-Sendable type %1 to %2 callee risks causing races in between %0 and %2 uses", - (StringRef, Type, ActorIsolation)) + (StringRef, Type, StringRef)) NOTE(regionbasedisolation_typed_sendneversendable_via_arg_callee, none, - "sending %0 value of non-Sendable type %1 to %2 %3 %4 risks causing races in between %0 and %2 uses", - (StringRef, Type, ActorIsolation, DescriptiveDeclKind, DeclName)) + "sending %0 value of non-Sendable type %1 to %2 %kind3 risks causing races in between %0 and %2 uses", + (StringRef, Type, StringRef, const ValueDecl *)) NOTE(regionbasedisolation_isolated_conformance_introduced, none, "isolated conformance to %kind0 can be introduced here", @@ -1097,10 +1098,10 @@ NOTE(regionbasedisolation_inout_sending_must_be_reinitialized, none, "'inout sending' parameter must be reinitialized before function exit with a non-actor isolated value", ()) ERROR(regionbasedisolation_inout_sending_cannot_be_actor_isolated, none, - "'inout sending' parameter %0 cannot be %1at end of function", + "'inout sending' parameter %0 cannot be %1 at end of function", (Identifier, StringRef)) NOTE(regionbasedisolation_inout_sending_cannot_be_actor_isolated_note, none, - "%1%0 risks causing races in between %1uses and caller uses since caller assumes value is not actor isolated", + "%1 %0 risks causing races in between %1 uses and caller uses since caller assumes value is not actor isolated", (Identifier, StringRef)) //=== @@ -1125,10 +1126,10 @@ NOTE(regionbasedisolation_out_sending_cannot_be_actor_isolated_note_named, none, // Example: returning main-actor isolated result to a custom-actor isolated context risks causing data races ERROR(rbi_isolation_crossing_result, none, "non-Sendable %0-typed result can not be returned from %1 %kind2 to %3 context", - (Type, ActorIsolation, const ValueDecl *, ActorIsolation)) + (Type, StringRef, const ValueDecl *, StringRef)) ERROR(rbi_isolation_crossing_result_no_decl, none, "non-Sendable %0-typed result can not be returned from %1 function to %2 context", - (Type, ActorIsolation, ActorIsolation)) + (Type, StringRef, StringRef)) NOTE(rbi_non_sendable_nominal,none, "%kind0 does not conform to the 'Sendable' protocol", (const ValueDecl *)) diff --git a/include/swift/AST/Identifier.h b/include/swift/AST/Identifier.h index 4724b5b202e3c..ee6a4c0a8b8d8 100644 --- a/include/swift/AST/Identifier.h +++ b/include/swift/AST/Identifier.h @@ -230,7 +230,7 @@ class Identifier { private: bool isOperatorSlow() const; }; - + class DeclName; class DeclNameRef; class ObjCSelector; diff --git a/include/swift/SILOptimizer/Analysis/RegionAnalysis.h b/include/swift/SILOptimizer/Analysis/RegionAnalysis.h index 7b81e1a3356df..eefdf5f47bbf9 100644 --- a/include/swift/SILOptimizer/Analysis/RegionAnalysis.h +++ b/include/swift/SILOptimizer/Analysis/RegionAnalysis.h @@ -179,16 +179,16 @@ class regionanalysisimpl::TrackableValueState { void removeFlag(TrackableValueFlag flag) { flagSet -= flag; } - void print(llvm::raw_ostream &os) const { + void print(SILFunction *fn, llvm::raw_ostream &os) const { os << "TrackableValueState[id: " << id << "][is_no_alias: " << (isNoAlias() ? "yes" : "no") << "][is_sendable: " << (isSendable() ? "yes" : "no") << "][region_value_kind: "; - getIsolationRegionInfo().printForOneLineLogging(os); + getIsolationRegionInfo().printForOneLineLogging(fn, os); os << "]."; } - SWIFT_DEBUG_DUMP { print(llvm::dbgs()); } + SWIFT_DEBUG_DUMPER(dump(SILFunction *fn)) { print(fn, llvm::dbgs()); } private: bool hasIsolationRegionInfo() const { return bool(regionInfo); } @@ -249,26 +249,26 @@ class regionanalysisimpl::TrackableValue { /// parameter. bool isSendingParameter() const; - void printIsolationInfo(SmallString<64> &outString) const { + void printIsolationInfo(SILFunction *fn, SmallString<64> &outString) const { llvm::raw_svector_ostream os(outString); - getIsolationRegionInfo().printForDiagnostics(os); + getIsolationRegionInfo().printForDiagnostics(fn, os); } - void print(llvm::raw_ostream &os) const { + void print(SILFunction *fn, llvm::raw_ostream &os) const { os << "TrackableValue. State: "; - valueState.print(os); + valueState.print(fn, os); os << "\n Rep Value: "; getRepresentative().print(os); } - void printVerbose(llvm::raw_ostream &os) const { + void printVerbose(SILFunction *fn, llvm::raw_ostream &os) const { os << "TrackableValue. State: "; - valueState.print(os); + valueState.print(fn, os); os << "\n Rep Value: " << getRepresentative(); } - SWIFT_DEBUG_DUMP { - print(llvm::dbgs()); + SWIFT_DEBUG_DUMPER(dump(SILFunction *fn)) { + print(fn, llvm::dbgs()); llvm::dbgs() << '\n'; } }; @@ -288,8 +288,8 @@ struct regionanalysisimpl::TrackableValueLookupResult { /// TrackableValue. std::optional base; - void print(llvm::raw_ostream &os) const; - SWIFT_DEBUG_DUMP { print(llvm::dbgs()); } + void print(SILFunction *fn, llvm::raw_ostream &os) const; + SWIFT_DEBUG_DUMPER(dumper(SILFunction *fn)) { print(fn, llvm::dbgs()); } }; class RegionAnalysis; @@ -390,6 +390,8 @@ class RegionAnalysisValueMap { return getUnderlyingTrackedValue(value).value; } + SILFunction *getFunction() const { return fn; } + /// Returns the value for this instruction if it isn't a fake "represenative /// value" to inject actor isolatedness. Asserts in such a case. SILValue getRepresentative(Element trackableValueID) const; diff --git a/include/swift/SILOptimizer/Utils/PartitionUtils.h b/include/swift/SILOptimizer/Utils/PartitionUtils.h index d0f99cd2d5cc6..dfddfb537a4e3 100644 --- a/include/swift/SILOptimizer/Utils/PartitionUtils.h +++ b/include/swift/SILOptimizer/Utils/PartitionUtils.h @@ -1598,9 +1598,32 @@ struct PartitionOpEvaluator { } private: - bool isConvertFunctionFromSendableType(SILValue equivalenceClassRep) const { + /// To work around not having isolation in interface types, the type checker + /// inserts casts and other AST nodes that are used to enrich the AST with + /// isolation information. This results in Sendable functions being + /// wrapped/converted/etc in ways that hide the Sendability. This helper looks + /// through these conversions/wrappers/thunks to see if the original + /// underlying function is Sendable. + /// + /// The two ways this can happen is that we either get an actual function_ref + /// that is Sendable or we get a convert function with a Sendable operand. + bool isHiddenSendableFunctionType(SILValue equivalenceClassRep) const { SILValue valueToTest = equivalenceClassRep; while (true) { + if (auto *pai = dyn_cast(valueToTest)) { + if (auto *calleeFunction = pai->getCalleeFunction()) { + if (pai->getNumArguments() >= 1 && + pai->getArgument(0)->getType().isFunction() && + calleeFunction->isThunk()) { + valueToTest = pai->getArgument(0); + continue; + } + + if (calleeFunction->getLoweredFunctionType()->isSendable()) + return true; + } + } + if (auto *i = dyn_cast(valueToTest)) { valueToTest = i->getOperand(); continue; @@ -1612,6 +1635,9 @@ struct PartitionOpEvaluator { break; } + if (auto *fn = dyn_cast(valueToTest)) + return fn->getReferencedFunction()->getLoweredFunctionType()->isSendable(); + auto *cvi = dyn_cast(valueToTest); if (!cvi) return false; @@ -1644,7 +1670,7 @@ struct PartitionOpEvaluator { // See if we have a convert function from a `@Sendable` type. In this // case, we want to squelch the error. - if (isConvertFunctionFromSendableType(equivalenceClassRep)) + if (isHiddenSendableFunctionType(equivalenceClassRep)) return; } @@ -1689,7 +1715,7 @@ struct PartitionOpEvaluator { // See if we have a convert function from a `@Sendable` type. In this // case, we want to squelch the error. - if (isConvertFunctionFromSendableType(equivalenceClassRep)) + if (isHiddenSendableFunctionType(equivalenceClassRep)) return; } } diff --git a/include/swift/SILOptimizer/Utils/SILIsolationInfo.h b/include/swift/SILOptimizer/Utils/SILIsolationInfo.h index c6f15400efe26..a57a50c9a950a 100644 --- a/include/swift/SILOptimizer/Utils/SILIsolationInfo.h +++ b/include/swift/SILOptimizer/Utils/SILIsolationInfo.h @@ -185,6 +185,10 @@ class SILIsolationInfo { /// parameter and should be allowed to merge into a self parameter. UnappliedIsolatedAnyParameter = 0x2, + /// If set, this was a TaskIsolated value from a nonisolated(nonsending) + /// parameter. + NonisolatedNonsendingTaskIsolated = 0x4, + /// The maximum number of bits used by a Flag. MaxNumBits = 3, }; @@ -317,6 +321,25 @@ class SILIsolationInfo { return result; } + bool isNonisolatedNonsendingTaskIsolated() const { + return getOptions().contains(Flag::NonisolatedNonsendingTaskIsolated); + } + + SILIsolationInfo + withNonisolatedNonsendingTaskIsolated(bool newValue = true) const { + assert(*this && "Cannot be unknown"); + assert(isTaskIsolated() && "Can only be task isolated"); + auto self = *this; + if (newValue) { + self.options = + (self.getOptions() | Flag::NonisolatedNonsendingTaskIsolated).toRaw(); + } else { + self.options = self.getOptions().toRaw() & + ~Options(Flag::NonisolatedNonsendingTaskIsolated).toRaw(); + } + return self; + } + /// Returns true if this actor isolation is derived from an unapplied /// isolation parameter. When merging, we allow for this to be merged with a /// more specific isolation kind. @@ -337,16 +360,16 @@ class SILIsolationInfo { return self; } - void print(llvm::raw_ostream &os) const; + void print(SILFunction *fn, llvm::raw_ostream &os) const; /// Print a textual representation of the text info that is meant to be /// included in other logging output for types that compose with /// SILIsolationInfo. As a result, we only print state that can fit on /// one line. - void printForOneLineLogging(llvm::raw_ostream &os) const; + void printForOneLineLogging(SILFunction *fn, llvm::raw_ostream &os) const; - SWIFT_DEBUG_DUMP { - print(llvm::dbgs()); + SWIFT_DEBUG_DUMPER(dump(SILFunction *fn)) { + print(fn, llvm::dbgs()); llvm::dbgs() << '\n'; } @@ -355,12 +378,20 @@ class SILIsolationInfo { /// /// We do this programatically since task-isolated code needs a very different /// form of diagnostic than other cases. - void printForCodeDiagnostic(llvm::raw_ostream &os) const; + void printForCodeDiagnostic(SILFunction *fn, llvm::raw_ostream &os) const; + + /// Overload of printForCodeDiagnostics that returns an interned StringRef + /// owned by the AST. + StringRef printForCodeDiagnostic(SILFunction *fn) const; - void printForDiagnostics(llvm::raw_ostream &os) const; + void printForDiagnostics(SILFunction *fn, llvm::raw_ostream &os) const; - SWIFT_DEBUG_DUMPER(dumpForDiagnostics()) { - printForDiagnostics(llvm::dbgs()); + /// Overload of printForDiagnostics that returns an interned StringRef owned + /// by the AST. + StringRef printForDiagnostics(SILFunction *fn) const; + + SWIFT_DEBUG_DUMPER(dumpForDiagnostics(SILFunction *fn)) { + printForDiagnostics(fn, llvm::dbgs()); llvm::dbgs() << '\n'; } @@ -549,6 +580,19 @@ class SILIsolationInfo { /// that the isolation and the isolated value match. bool isEqual(const SILIsolationInfo &other) const; + /// A helper function that prints ActorIsolation like we normally do except + /// that it prints nonisolated(nonsending) as nonisolated. This is needed in + /// certain cases when talking about use-after-free uses in send non sendable. + static void printActorIsolationForDiagnostics( + SILFunction *fn, ActorIsolation iso, llvm::raw_ostream &os, + StringRef openingQuotationMark = "'", bool asNoun = false); + + /// Overload for printActorIsolationForDiagnostics that produces a StringRef. + static StringRef + printActorIsolationForDiagnostics(SILFunction *fn, ActorIsolation iso, + StringRef openingQuotationMark = "'", + bool asNoun = false); + void Profile(llvm::FoldingSetNodeID &id) const; private: @@ -612,43 +656,33 @@ class SILDynamicMergedIsolationInfo { SILIsolationInfo::getDisconnected(isUnsafeNonIsolated)); } - SWIFT_DEBUG_DUMP { innerInfo.dump(); } + SWIFT_DEBUG_DUMPER(dump(SILFunction *fn)) { innerInfo.dump(fn); } - void printForDiagnostics(llvm::raw_ostream &os) const { - innerInfo.printForDiagnostics(os); + void printForDiagnostics(SILFunction *fn, llvm::raw_ostream &os) const { + innerInfo.printForDiagnostics(fn, os); } - SWIFT_DEBUG_DUMPER(dumpForDiagnostics()) { - innerInfo.dumpForDiagnostics(); + StringRef printForDiagnostics(SILFunction *fn) const { + return innerInfo.printForDiagnostics(fn); } - void printForCodeDiagnostic(llvm::raw_ostream &os) const { - innerInfo.printForCodeDiagnostic(os); + SWIFT_DEBUG_DUMPER(dumpForDiagnostics(SILFunction *fn)) { + innerInfo.dumpForDiagnostics(fn); } - void printForOneLineLogging(llvm::raw_ostream &os) const { - innerInfo.printForOneLineLogging(os); + void printForCodeDiagnostic(SILFunction *fn, llvm::raw_ostream &os) const { + innerInfo.printForCodeDiagnostic(fn, os); } -}; -} // namespace swift - -namespace llvm { - -inline llvm::raw_ostream & -operator<<(llvm::raw_ostream &os, - const swift::SILIsolationInfo &isolationInfo) { - isolationInfo.printForOneLineLogging(os); - return os; -} + StringRef printForCodeDiagnostic(SILFunction *fn) const { + return innerInfo.printForCodeDiagnostic(fn); + } -inline llvm::raw_ostream & -operator<<(llvm::raw_ostream &os, - const swift::SILDynamicMergedIsolationInfo &isolationInfo) { - isolationInfo.printForOneLineLogging(os); - return os; -} + void printForOneLineLogging(SILFunction *fn, llvm::raw_ostream &os) const { + innerInfo.printForOneLineLogging(fn, os); + } +}; -} // namespace llvm +} // namespace swift #endif diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index f33cc526bd2d8..15686b18ac236 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -497,6 +497,10 @@ namespace { RValue emitFunctionCvtFromExecutionCallerToGlobalActor(FunctionConversionExpr *E, SGFContext C); + + RValue emitFunctionCvtForNonisolatedNonsendingClosureExpr( + FunctionConversionExpr *E, SGFContext C); + RValue visitActorIsolationErasureExpr(ActorIsolationErasureExpr *E, SGFContext C); RValue visitExtractFunctionIsolationExpr(ExtractFunctionIsolationExpr *E, @@ -2033,6 +2037,44 @@ RValueEmitter::emitFunctionCvtToExecutionCaller(FunctionConversionExpr *e, return RValue(SGF, e, destType, result); } +RValue RValueEmitter::emitFunctionCvtForNonisolatedNonsendingClosureExpr( + FunctionConversionExpr *E, SGFContext C) { + // The specific AST pattern for this looks as follows: + // + // (function_conversion_expr type="nonisolated(nonsending) () async -> Void" + // (closure_expr type="() async -> ()" isolated_to_caller_isolation)) + CanAnyFunctionType destType = + cast(E->getType()->getCanonicalType()); + auto subExpr = E->getSubExpr()->getSemanticsProvidingExpr(); + + // If we do not have a closure or if that closure is not caller isolation + // inheriting, bail. + auto *closureExpr = dyn_cast(subExpr); + if (!closureExpr || + !closureExpr->getActorIsolation().isCallerIsolationInheriting()) + return RValue(); + + // Then grab our closure type... make sure it is non isolated and then make + // sure it is the same as our destType but with nonisolated. + CanAnyFunctionType closureType = + cast(closureExpr->getType()->getCanonicalType()); + if (!closureType->getIsolation().isNonIsolated() || + closureType != + destType->withIsolation(FunctionTypeIsolation::forNonIsolated()) + ->getCanonicalType()) + return RValue(); + + // NOTE: This is a partial inline of getClosureTypeInfo. We do this so we have + // more control and make this change less viral in the compiler for 6.2. + auto newExtInfo = closureType->getExtInfo().withIsolation( + FunctionTypeIsolation::forNonIsolatedCaller()); + closureType = closureType.withExtInfo(newExtInfo); + auto info = SGF.getFunctionTypeInfo(closureType); + + auto closure = emitClosureReference(closureExpr, info); + return RValue(SGF, closureExpr, destType, closure); +} + RValue RValueEmitter::emitFunctionCvtFromExecutionCallerToGlobalActor( FunctionConversionExpr *e, SGFContext C) { // We are pattern matching a conversion sequence like the following: @@ -2144,6 +2186,28 @@ RValue RValueEmitter::visitFunctionConversionExpr(FunctionConversionExpr *e, // TODO: Move this up when we can emit closures directly with C calling // convention. auto subExpr = e->getSubExpr()->getSemanticsProvidingExpr(); + + // Before we go any further into emitting the convert function expr, see if + // our SubExpr is a ClosureExpr with the exact same type as our + // FunctionConversionExpr except with the FunctionConversionExpr adding + // nonisolated(nonsending). Then see if the ClosureExpr itself (even though it + // is not nonisolated(nonsending) typed is considered to have + // nonisolated(nonsending) isolation. In such a case, emit the closure + // directly. We are going to handle it especially in closure emission to work + // around the missing information in the type. + // + // DISCUSSION: We need to do this here since in the Expression TypeChecker we + // do not have access to capture information when we would normally want to + // mark the closure type as being nonisolated(nonsending). As a result, we + // cannot know if the nonisolated(nonsending) should be overridden by for + // example an actor that is captured by the closure. So to work around this in + // Sema, we still mark the ClosureExpr as having the appropriate isolation + // even though its type does not have it... and then we work around this here + // and also in getClosureTypeInfo. + if (destType->getIsolation().isNonIsolatedCaller()) + if (auto rv = emitFunctionCvtForNonisolatedNonsendingClosureExpr(e, C)) + return rv; + // Look through `as` type ascriptions that don't induce bridging too. while (auto subCoerce = dyn_cast(subExpr)) { // Coercions that introduce bridging aren't simple type ascriptions. diff --git a/lib/SILOptimizer/Analysis/RegionAnalysis.cpp b/lib/SILOptimizer/Analysis/RegionAnalysis.cpp index 79be3cf57cb2e..1d19efe5c1144 100644 --- a/lib/SILOptimizer/Analysis/RegionAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/RegionAnalysis.cpp @@ -820,7 +820,7 @@ void RegionAnalysisValueMap::print(llvm::raw_ostream &os) const { for (auto p : temp) { os << "%%" << p.first << ": "; auto value = getValueForId(Element(p.first)); - value->print(os); + value->print(getFunction(), os); } #endif } @@ -1127,12 +1127,13 @@ bool TrackableValue::isSendingParameter() const { // MARK: TrackableValueLookupResult //===----------------------------------------------------------------------===// -void TrackableValueLookupResult::print(llvm::raw_ostream &os) const { +void TrackableValueLookupResult::print(SILFunction *fn, + llvm::raw_ostream &os) const { os << "Value:\n"; - value.print(os); + value.print(fn, os); if (base) { os << "Base:\n"; - base->print(os); + base->print(fn, os); } } @@ -1618,6 +1619,11 @@ struct PartitionOpBuilder { /// generating partition ops. SmallVector currentInstPartitionOps; + SILFunction *getFunction() const { + assert(currentInst); + return currentInst->getFunction(); + } + void reset(SILInstruction *inst) { currentInst = inst; currentInstPartitionOps.clear(); @@ -1978,7 +1984,8 @@ class PartitionOpTranslator { isNonSendableType(val->getType())) { auto trackVal = getTrackableValue(val, true); (void)trackVal; - REGIONBASEDISOLATION_LOG(trackVal.print(llvm::dbgs())); + REGIONBASEDISOLATION_LOG( + trackVal.print(val->getFunction(), llvm::dbgs())); continue; } if (auto *pbi = dyn_cast(val)) { @@ -2055,7 +2062,7 @@ class PartitionOpTranslator { // send list and to the region join list. REGIONBASEDISOLATION_LOG( llvm::dbgs() << " %%" << value.getID() << ": "; - value.print(llvm::dbgs()); llvm::dbgs() << *arg); + value.print(function, llvm::dbgs()); llvm::dbgs() << *arg); nonSendableJoinedIndices.push_back(value.getID()); } else { REGIONBASEDISOLATION_LOG(llvm::dbgs() << " Sendable: " << *arg); @@ -2228,14 +2235,15 @@ class PartitionOpTranslator { REGIONBASEDISOLATION_LOG( llvm::dbgs() << "Merge Failure!\n" << "Original Info: "; - if (originalMergedInfo) - originalMergedInfo->printForDiagnostics(llvm::dbgs()); + if (originalMergedInfo) originalMergedInfo->printForDiagnostics( + builder.getFunction(), llvm::dbgs()); else llvm::dbgs() << "nil"; llvm::dbgs() << "\nValue Rep: " << value.getRepresentative().getValue(); llvm::dbgs() << "Original Src: " << src; llvm::dbgs() << "Value Info: "; - value.getIsolationRegionInfo().printForDiagnostics(llvm::dbgs()); + value.getIsolationRegionInfo().printForDiagnostics( + builder.getFunction(), llvm::dbgs()); llvm::dbgs() << "\n"); builder.addUnknownPatternError(src); continue; @@ -3220,7 +3228,7 @@ void PartitionOpBuilder::print(llvm::raw_ostream &os) const { auto trackableValue = translator->getValueForId(opArg); assert(trackableValue); llvm::dbgs() << "State: %%" << opArg << ". "; - trackableValue->getValueState().print(llvm::dbgs()); + trackableValue->getValueState().print(getFunction(), llvm::dbgs()); llvm::dbgs() << "\n Rep Value: " << trackableValue->getRepresentative(); if (auto value = trackableValue->getRepresentative().maybeGetValue()) { @@ -4310,7 +4318,7 @@ static FunctionTest RegionAnalysisValueMap valueMap(&function); auto value = arguments.takeValue(); auto trackableValue = valueMap.getTrackableValue(value); - trackableValue.print(llvm::outs()); + trackableValue.print(&function, llvm::outs()); llvm::outs() << '\n'; }); diff --git a/lib/SILOptimizer/Mandatory/DataflowDiagnostics.cpp b/lib/SILOptimizer/Mandatory/DataflowDiagnostics.cpp index 5e161eb690350..ea8397a6fd295 100644 --- a/lib/SILOptimizer/Mandatory/DataflowDiagnostics.cpp +++ b/lib/SILOptimizer/Mandatory/DataflowDiagnostics.cpp @@ -69,10 +69,9 @@ static void diagnoseMissingReturn(const UnreachableInst *UI, Context.Diags.diagnose(expr->getStartLoc(), diag::missing_return_closure, ResTy); } else { - auto *DC = FLoc.getAsDeclContext(); - assert(DC && DC->getAsDecl() && "not a declaration?"); + auto *FD = FLoc.castToASTNode(); Context.Diags.diagnose(expr->getStartLoc(), diag::missing_return_decl, - ResTy, DC->getAsDecl()->getDescriptiveKind()); + ResTy, FD); } Context.Diags .diagnose(expr->getStartLoc(), diag::missing_return_last_expr_note) @@ -89,12 +88,10 @@ static void diagnoseMissingReturn(const UnreachableInst *UI, : diag::missing_return_closure; diagnose(Context, L.getEndSourceLoc(), diagID, ResTy); } else { - auto *DC = FLoc.getAsDeclContext(); - assert(DC && DC->getAsDecl() && "not a declaration?"); + auto *FD = FLoc.castToASTNode(); auto diagID = isNoReturnFn ? diag::missing_never_call_decl : diag::missing_return_decl; - diagnose(Context, L.getEndSourceLoc(), diagID, ResTy, - DC->getAsDecl()->getDescriptiveKind()); + diagnose(Context, L.getEndSourceLoc(), diagID, ResTy, FD); } } diff --git a/lib/SILOptimizer/Mandatory/FlowIsolation.cpp b/lib/SILOptimizer/Mandatory/FlowIsolation.cpp index 26cd098062d61..41bd158bf2070 100644 --- a/lib/SILOptimizer/Mandatory/FlowIsolation.cpp +++ b/lib/SILOptimizer/Mandatory/FlowIsolation.cpp @@ -484,9 +484,9 @@ void Info::diagnoseAll(AnalysisInfo &info, bool forDeinit, VarDecl *var = cast(use)->getField(); diag.diagnose(illegalLoc.getSourceLoc(), diag::isolated_after_nonisolated, - forDeinit, var->getDescriptiveKind(), var->getName()) - .highlight(illegalLoc.getSourceRange()) - .warnUntilSwiftVersion(6); + forDeinit, var) + .highlight(illegalLoc.getSourceRange()) + .warnUntilSwiftVersion(6); // after , ... can't use self anymore, etc ... // example: diff --git a/lib/SILOptimizer/Mandatory/SendNonSendable.cpp b/lib/SILOptimizer/Mandatory/SendNonSendable.cpp index 8a34796fe6d95..1f1fdf9e1a253 100644 --- a/lib/SILOptimizer/Mandatory/SendNonSendable.cpp +++ b/lib/SILOptimizer/Mandatory/SendNonSendable.cpp @@ -149,17 +149,16 @@ static std::optional getDeclRefForCallee(SILInstruction *inst) { } } -static std::optional> -getSendingApplyCalleeInfo(SILInstruction *inst) { +static std::optional getSendingApplyCallee(SILInstruction *inst) { auto declRef = getDeclRefForCallee(inst); if (!declRef) return {}; auto *decl = declRef->getDecl(); - if (!decl || !decl->hasName()) + if (!decl) return {}; - return {{decl->getDescriptiveKind(), decl->getName()}}; + return decl; } static Expr *inferArgumentExprFromApplyExpr(ApplyExpr *sourceApply, @@ -672,10 +671,9 @@ class UseAfterSendDiagnosticEmitter { getFunction()); } - /// If we can find a callee decl name, return that. None otherwise. - std::optional> - getSendingCalleeInfo() const { - return getSendingApplyCalleeInfo(sendingOp->getUser()); + /// Attempts to retrieve and return the callee declaration. + std::optional getSendingCallee() const { + return getSendingApplyCallee(sendingOp->getUser()); } void @@ -688,26 +686,25 @@ class UseAfterSendDiagnosticEmitter { .limitBehaviorIf(getBehaviorLimit()); // Then emit the note with greater context. - SmallString<64> descriptiveKindStr; - { - if (!namedValuesIsolationInfo.isDisconnected()) { - llvm::raw_svector_ostream os(descriptiveKindStr); - namedValuesIsolationInfo.printForDiagnostics(os); - os << ' '; - } - } - - if (auto calleeInfo = getSendingCalleeInfo()) { + auto descriptiveKindStr = + namedValuesIsolationInfo.printForDiagnostics(getFunction()); + auto calleeIsolationStr = + SILIsolationInfo::printActorIsolationForDiagnostics( + getFunction(), isolationCrossing.getCalleeIsolation()); + auto callerIsolationStr = + SILIsolationInfo::printActorIsolationForDiagnostics( + getFunction(), isolationCrossing.getCallerIsolation()); + + bool isDisconnected = namedValuesIsolationInfo.isDisconnected(); + if (auto callee = getSendingCallee()) { diagnoseNote( loc, diag::regionbasedisolation_named_info_send_yields_race_callee, - name, descriptiveKindStr, isolationCrossing.getCalleeIsolation(), - calleeInfo->first, calleeInfo->second, - isolationCrossing.getCallerIsolation()); + isDisconnected, name, descriptiveKindStr, calleeIsolationStr, + callee.value(), callerIsolationStr); } else { diagnoseNote(loc, diag::regionbasedisolation_named_info_send_yields_race, - name, descriptiveKindStr, - isolationCrossing.getCalleeIsolation(), - isolationCrossing.getCallerIsolation()); + isDisconnected, name, descriptiveKindStr, calleeIsolationStr, + callerIsolationStr); } emitRequireInstDiagnostics(); } @@ -716,27 +713,27 @@ class UseAfterSendDiagnosticEmitter { emitNamedIsolationCrossingError(SILLocation loc, Identifier name, SILIsolationInfo namedValuesIsolationInfo, ApplyIsolationCrossing isolationCrossing, - DeclName calleeDeclName, - DescriptiveDeclKind calleeDeclKind) { + const ValueDecl *callee) { // Emit the short error. diagnoseError(loc, diag::regionbasedisolation_named_send_yields_race, name) .highlight(loc.getSourceRange()) .limitBehaviorIf(getBehaviorLimit()); // Then emit the note with greater context. - SmallString<64> descriptiveKindStr; - { - if (!namedValuesIsolationInfo.isDisconnected()) { - llvm::raw_svector_ostream os(descriptiveKindStr); - namedValuesIsolationInfo.printForDiagnostics(os); - os << ' '; - } - } + auto descriptiveKindStr = + namedValuesIsolationInfo.printForDiagnostics(getFunction()); + auto calleeIsolationStr = + SILIsolationInfo::printActorIsolationForDiagnostics( + getFunction(), isolationCrossing.getCalleeIsolation()); + auto callerIsolationStr = + SILIsolationInfo::printActorIsolationForDiagnostics( + getFunction(), isolationCrossing.getCallerIsolation()); + bool isDisconnected = namedValuesIsolationInfo.isDisconnected(); - diagnoseNote( - loc, diag::regionbasedisolation_named_info_send_yields_race_callee, - name, descriptiveKindStr, isolationCrossing.getCalleeIsolation(), - calleeDeclKind, calleeDeclName, isolationCrossing.getCallerIsolation()); + diagnoseNote(loc, + diag::regionbasedisolation_named_info_send_yields_race_callee, + isDisconnected, name, descriptiveKindStr, calleeIsolationStr, + callee, callerIsolationStr); emitRequireInstDiagnostics(); } @@ -759,15 +756,20 @@ class UseAfterSendDiagnosticEmitter { .highlight(loc.getSourceRange()) .limitBehaviorIf(getBehaviorLimit()); - if (auto calleeInfo = getSendingCalleeInfo()) { + auto calleeIsolationStr = + SILIsolationInfo::printActorIsolationForDiagnostics( + getFunction(), isolationCrossing.getCalleeIsolation()); + auto callerIsolationStr = + SILIsolationInfo::printActorIsolationForDiagnostics( + getFunction(), isolationCrossing.getCallerIsolation()); + + if (auto callee = getSendingCallee()) { diagnoseNote(loc, diag::regionbasedisolation_type_use_after_send_callee, - inferredType, isolationCrossing.getCalleeIsolation(), - calleeInfo->first, calleeInfo->second, - isolationCrossing.getCallerIsolation()); + inferredType, calleeIsolationStr, callee.value(), + callerIsolationStr); } else { diagnoseNote(loc, diag::regionbasedisolation_type_use_after_send, - inferredType, isolationCrossing.getCalleeIsolation(), - isolationCrossing.getCallerIsolation()); + inferredType, calleeIsolationStr, callerIsolationStr); } emitRequireInstDiagnostics(); } @@ -793,10 +795,10 @@ class UseAfterSendDiagnosticEmitter { inferredType) .highlight(loc.getSourceRange()) .limitBehaviorIf(getBehaviorLimit()); - if (auto calleeInfo = getSendingCalleeInfo()) { + if (auto callee = getSendingCallee()) { diagnoseNote(loc, diag::regionbasedisolation_typed_use_after_sending_callee, - inferredType, calleeInfo->first, calleeInfo->second); + inferredType, callee.value()); } else { diagnoseNote(loc, diag::regionbasedisolation_typed_use_after_sending, inferredType); @@ -813,19 +815,19 @@ class UseAfterSendDiagnosticEmitter { .highlight(loc.getSourceRange()) .limitBehaviorIf(getBehaviorLimit()); - SmallString<64> descriptiveKindStr; - { - if (!namedValuesIsolationInfo.isDisconnected()) { - llvm::raw_svector_ostream os(descriptiveKindStr); - namedValuesIsolationInfo.printForDiagnostics(os); - os << ' '; - } - } - - diagnoseNote( - loc, diag::regionbasedisolation_named_isolated_closure_yields_race, - descriptiveKindStr, name, isolationCrossing.getCalleeIsolation(), - isolationCrossing.getCallerIsolation()) + auto descriptiveKindStr = + namedValuesIsolationInfo.printForDiagnostics(getFunction()); + auto calleeIsolationStr = + SILIsolationInfo::printActorIsolationForDiagnostics( + getFunction(), isolationCrossing.getCalleeIsolation()); + auto callerIsolationStr = + SILIsolationInfo::printActorIsolationForDiagnostics( + getFunction(), isolationCrossing.getCallerIsolation()); + bool isDisconnected = namedValuesIsolationInfo.isDisconnected(); + diagnoseNote(loc, + diag::regionbasedisolation_named_isolated_closure_yields_race, + isDisconnected, descriptiveKindStr, name, calleeIsolationStr, + callerIsolationStr) .highlight(loc.getSourceRange()); emitRequireInstDiagnostics(); } @@ -837,10 +839,17 @@ class UseAfterSendDiagnosticEmitter { inferredType) .highlight(loc.getSourceRange()) .limitBehaviorIf(getBehaviorLimit()); + + auto calleeIsolationStr = + SILIsolationInfo::printActorIsolationForDiagnostics( + getFunction(), isolationCrossing.getCalleeIsolation()); + auto callerIsolationStr = + SILIsolationInfo::printActorIsolationForDiagnostics( + getFunction(), isolationCrossing.getCallerIsolation()); + diagnoseNote(loc, diag::regionbasedisolation_type_isolated_capture_yields_race, - inferredType, isolationCrossing.getCalleeIsolation(), - isolationCrossing.getCallerIsolation()); + inferredType, calleeIsolationStr, callerIsolationStr); emitRequireInstDiagnostics(); } @@ -1106,8 +1115,7 @@ struct UseAfterSendDiagnosticInferrer::AutoClosureWalker : ASTWalker { if (valueDecl->hasName()) { foundTypeInfo.diagnosticEmitter.emitNamedIsolationCrossingError( foundTypeInfo.baseLoc, targetDecl->getBaseIdentifier(), - targetDeclIsolationInfo, *isolationCrossing, - valueDecl->getName(), valueDecl->getDescriptiveKind()); + targetDeclIsolationInfo, *isolationCrossing, valueDecl); continue; } @@ -1341,10 +1349,9 @@ class SendNeverSentDiagnosticEmitter { getOperand()->getFunction()); } - /// If we can find a callee decl name, return that. None otherwise. - std::optional> - getSendingCalleeInfo() const { - return getSendingApplyCalleeInfo(sendingOperand->getUser()); + /// Attempts to retrieve and return the callee declaration. + std::optional getSendingCallee() const { + return getSendingApplyCallee(sendingOperand->getUser()); } SILLocation getLoc() const { return sendingOperand->getUser()->getLoc(); } @@ -1378,40 +1385,41 @@ class SendNeverSentDiagnosticEmitter { .highlight(loc.getSourceRange()) .limitBehaviorIf(getBehaviorLimit()); - SmallString<64> descriptiveKindStr; - { - llvm::raw_svector_ostream os(descriptiveKindStr); - getIsolationRegionInfo().printForDiagnostics(os); - } + auto descriptiveKindStr = + getIsolationRegionInfo().printForDiagnostics(getFunction()); + auto calleeIsolationStr = + SILIsolationInfo::printActorIsolationForDiagnostics( + getFunction(), crossing.getCalleeIsolation()); - if (auto calleeInfo = getSendingCalleeInfo()) { + if (auto callee = getSendingCallee()) { diagnoseNote( loc, diag::regionbasedisolation_typed_sendneversendable_via_arg_callee, - descriptiveKindStr, inferredType, crossing.getCalleeIsolation(), - calleeInfo->first, calleeInfo->second); + descriptiveKindStr, inferredType, calleeIsolationStr, callee.value()); } else { - diagnoseNote( - loc, diag::regionbasedisolation_typed_sendneversendable_via_arg, - descriptiveKindStr, inferredType, crossing.getCalleeIsolation()); + diagnoseNote(loc, + diag::regionbasedisolation_typed_sendneversendable_via_arg, + descriptiveKindStr, inferredType, calleeIsolationStr); } } void emitNamedFunctionArgumentClosure(SILLocation loc, Identifier name, ApplyIsolationCrossing crossing) { emitNamedOnlyError(loc, name); - SmallString<64> descriptiveKindStr; - { - if (!getIsolationRegionInfo().isDisconnected()) { - llvm::raw_svector_ostream os(descriptiveKindStr); - getIsolationRegionInfo().printForDiagnostics(os); - os << ' '; - } - } + + auto descriptiveKindStr = + getIsolationRegionInfo().printForDiagnostics(getFunction()); + auto calleeIsolationStr = + SILIsolationInfo::printActorIsolationForDiagnostics( + getFunction(), crossing.getCalleeIsolation()); + auto callerIsolationStr = + SILIsolationInfo::printActorIsolationForDiagnostics( + getFunction(), crossing.getCallerIsolation()); + bool isDisconnected = getIsolationRegionInfo().isDisconnected(); diagnoseNote(loc, diag::regionbasedisolation_named_isolated_closure_yields_race, - descriptiveKindStr, name, crossing.getCalleeIsolation(), - crossing.getCallerIsolation()) + isDisconnected, descriptiveKindStr, name, calleeIsolationStr, + callerIsolationStr) .highlight(loc.getSourceRange()); } @@ -1422,17 +1430,13 @@ class SendNeverSentDiagnosticEmitter { .highlight(loc.getSourceRange()) .limitBehaviorIf(getBehaviorLimit()); - SmallString<64> descriptiveKindStr; - { - llvm::raw_svector_ostream os(descriptiveKindStr); - getIsolationRegionInfo().printForDiagnostics(os); - } + auto descriptiveKindStr = + getIsolationRegionInfo().printForDiagnostics(getFunction()); - if (auto calleeInfo = getSendingCalleeInfo()) { + if (auto callee = getSendingCallee()) { diagnoseNote( loc, diag::regionbasedisolation_typed_tns_passed_to_sending_callee, - descriptiveKindStr, inferredType, calleeInfo->first, - calleeInfo->second); + descriptiveKindStr, inferredType, callee.value()); } else { diagnoseNote(loc, diag::regionbasedisolation_typed_tns_passed_to_sending, descriptiveKindStr, inferredType); @@ -1445,11 +1449,8 @@ class SendNeverSentDiagnosticEmitter { void emitClosureErrorWithCapturedActor(Operand *partialApplyOp, Operand *actualUse, SILArgument *fArg) { - SmallString<64> descriptiveKindStr; - { - llvm::raw_svector_ostream os(descriptiveKindStr); - getIsolationRegionInfo().getIsolationInfo().printForCodeDiagnostic(os); - } + auto descriptiveKindStr = + getIsolationRegionInfo().printForCodeDiagnostic(getFunction()); diagnoseError(partialApplyOp, diag::regionbasedisolation_typed_tns_passed_sending_closure, @@ -1457,11 +1458,8 @@ class SendNeverSentDiagnosticEmitter { .limitBehaviorIf(getDiagnosticBehaviorLimitForOperands( actualUse->getFunction(), {actualUse})); - descriptiveKindStr.clear(); - { - llvm::raw_svector_ostream os(descriptiveKindStr); - getIsolationRegionInfo().getIsolationInfo().printForDiagnostics(os); - } + descriptiveKindStr = + getIsolationRegionInfo().printForDiagnostics(getFunction()); diagnoseNote(actualUse, diag::regionbasedisolation_closure_captures_actor, fArg->getDecl()->getName(), descriptiveKindStr); } @@ -1476,11 +1474,8 @@ class SendNeverSentDiagnosticEmitter { void emitSendingClosureParamDirectlyIsolated(Operand *partialApplyOp, Operand *actualUse, SILArgument *fArg) { - SmallString<64> descriptiveKindStr; - { - llvm::raw_svector_ostream os(descriptiveKindStr); - getIsolationRegionInfo().getIsolationInfo().printForCodeDiagnostic(os); - } + auto descriptiveKindStr = + getIsolationRegionInfo().printForCodeDiagnostic(getFunction()); diagnoseError(partialApplyOp, diag::regionbasedisolation_typed_tns_passed_sending_closure, @@ -1494,8 +1489,7 @@ class SendNeverSentDiagnosticEmitter { fArg->getType().is()) { auto diag = diag:: regionbasedisolation_typed_tns_passed_to_sending_closure_helper_have_boxed_value_task_isolated; - diagnoseNote(actualUse, diag, fArg->getDecl()->getName(), - fArg->getDecl()->getDescriptiveKind()); + diagnoseNote(actualUse, diag, fArg->getDecl()); return; } @@ -1505,11 +1499,8 @@ class SendNeverSentDiagnosticEmitter { return; } - descriptiveKindStr.clear(); - { - llvm::raw_svector_ostream os(descriptiveKindStr); - getIsolationRegionInfo().printForDiagnostics(os); - } + descriptiveKindStr = + getIsolationRegionInfo().printForDiagnostics(getFunction()); auto diag = diag:: regionbasedisolation_typed_tns_passed_to_sending_closure_helper_have_value; @@ -1526,11 +1517,8 @@ class SendNeverSentDiagnosticEmitter { return; } - SmallString<64> descriptiveKindStr; - { - llvm::raw_svector_ostream os(descriptiveKindStr); - getIsolationRegionInfo()->printForCodeDiagnostic(os); - } + auto descriptiveKindStr = + getIsolationRegionInfo()->printForCodeDiagnostic(getFunction()); auto emitMainError = [&] { auto behaviorLimit = getDiagnosticBehaviorLimitForOperands( @@ -1562,11 +1550,8 @@ class SendNeverSentDiagnosticEmitter { } emitMainError(); - descriptiveKindStr.clear(); - { - llvm::raw_svector_ostream os(descriptiveKindStr); - getIsolationRegionInfo().printForDiagnostics(os); - } + descriptiveKindStr = + getIsolationRegionInfo().printForDiagnostics(getFunction()); auto diag = diag:: regionbasedisolation_typed_tns_passed_to_sending_closure_helper_have_value_region; diagnoseNote(actualUseInfo->first, diag, descriptiveKindStr, @@ -1607,11 +1592,8 @@ class SendNeverSentDiagnosticEmitter { "Should never be disconnected?!"); emitNamedOnlyError(loc, name); - SmallString<64> descriptiveKindStr; - { - llvm::raw_svector_ostream os(descriptiveKindStr); - getIsolationRegionInfo().printForDiagnostics(os); - } + auto descriptiveKindStr = + getIsolationRegionInfo().printForDiagnostics(getFunction()); diagnoseNote(loc, diag::regionbasedisolation_named_send_nt_asynclet_capture, name, descriptiveKindStr); @@ -1620,62 +1602,44 @@ class SendNeverSentDiagnosticEmitter { void emitNamedIsolation(SILLocation loc, Identifier name, ApplyIsolationCrossing isolationCrossing) { emitNamedOnlyError(loc, name); - SmallString<64> descriptiveKindStr; - SmallString<64> descriptiveKindStrWithSpace; - { - if (!getIsolationRegionInfo().isDisconnected()) { - { - llvm::raw_svector_ostream os(descriptiveKindStr); - getIsolationRegionInfo().printForDiagnostics(os); - } - descriptiveKindStrWithSpace = descriptiveKindStr; - descriptiveKindStrWithSpace.push_back(' '); - } - } - if (auto calleeInfo = getSendingCalleeInfo()) { + + auto descriptiveKindStr = + getIsolationRegionInfo().printForDiagnostics(getFunction()); + auto calleeIsolationStr = + SILIsolationInfo::printActorIsolationForDiagnostics( + getFunction(), isolationCrossing.getCalleeIsolation()); + bool isDisconnected = getIsolationRegionInfo().isDisconnected(); + + if (auto callee = getSendingCallee()) { diagnoseNote(loc, diag::regionbasedisolation_named_send_never_sendable_callee, - name, descriptiveKindStrWithSpace, - isolationCrossing.getCalleeIsolation(), calleeInfo->first, - calleeInfo->second, descriptiveKindStr); + isDisconnected, name, descriptiveKindStr, calleeIsolationStr, + callee.value(), descriptiveKindStr); } else { diagnoseNote(loc, diag::regionbasedisolation_named_send_never_sendable, - name, descriptiveKindStrWithSpace, - isolationCrossing.getCalleeIsolation(), descriptiveKindStr); + isDisconnected, name, descriptiveKindStr, calleeIsolationStr, + descriptiveKindStr); } } void emitNamedSendingNeverSendableToSendingParam(SILLocation loc, Identifier varName) { emitNamedOnlyError(loc, varName); - SmallString<64> descriptiveKindStr; - { - if (!getIsolationRegionInfo().isDisconnected()) { - llvm::raw_svector_ostream os(descriptiveKindStr); - getIsolationRegionInfo().printForDiagnostics(os); - os << ' '; - } - } + + auto descriptiveKindStr = + getIsolationRegionInfo().printForDiagnostics(getFunction()); + bool isDisconnected = getIsolationRegionInfo().isDisconnected(); auto diag = diag::regionbasedisolation_named_send_into_sending_param; - diagnoseNote(loc, diag, descriptiveKindStr, varName); + diagnoseNote(loc, diag, isDisconnected, descriptiveKindStr, varName); } void emitNamedSendingReturn(SILLocation loc, Identifier varName) { emitNamedOnlyError(loc, varName); - SmallString<64> descriptiveKindStr; - SmallString<64> descriptiveKindStrWithSpace; - { - if (!getIsolationRegionInfo().isDisconnected()) { - { - llvm::raw_svector_ostream os(descriptiveKindStr); - getIsolationRegionInfo().printForDiagnostics(os); - } - descriptiveKindStrWithSpace = descriptiveKindStr; - descriptiveKindStrWithSpace.push_back(' '); - } - } + auto descriptiveKindStr = + getIsolationRegionInfo().printForDiagnostics(getFunction()); + bool isDisconnected = getIsolationRegionInfo().isDisconnected(); auto diag = diag::regionbasedisolation_named_nosend_send_into_result; - diagnoseNote(loc, diag, descriptiveKindStrWithSpace, varName, + diagnoseNote(loc, diag, isDisconnected, descriptiveKindStr, varName, descriptiveKindStr); } @@ -1990,7 +1954,6 @@ bool SentNeverSendableDiagnosticInferrer::run() { return true; // See if we can infer a name from the value. - SmallString<64> resultingName; if (auto varName = inferNameHelper(op->get())) { diagnosticEmitter.emitNamedSendingNeverSendableToSendingParam( loc, *varName); @@ -2031,7 +1994,6 @@ bool SentNeverSendableDiagnosticInferrer::run() { } // See if we can infer a name from the value. - SmallString<64> resultingName; if (auto name = inferNameHelper(op->get())) { diagnosticEmitter.emitNamedIsolation(loc, *name, *isolation); return true; @@ -2079,7 +2041,6 @@ bool SentNeverSendableDiagnosticInferrer::run() { }) && "All result info must be the same... if that changes... update " "this code!"); - SmallString<64> resultingName; if (auto name = inferNameHelper(op->get())) { diagnosticEmitter.emitNamedSendingReturn(loc, *name); return true; @@ -2228,12 +2189,8 @@ void InOutSendingNotDisconnectedDiagnosticEmitter::emit() { } // Then emit the note with greater context. - SmallString<64> descriptiveKindStr; - { - llvm::raw_svector_ostream os(descriptiveKindStr); - actorIsolatedRegionInfo.printForDiagnostics(os); - os << ' '; - } + auto descriptiveKindStr = + actorIsolatedRegionInfo.printForDiagnostics(getFunction()); diagnoseError( functionExitingInst, @@ -2388,11 +2345,8 @@ static SILValue findOutParameter(SILValue v) { void AssignIsolatedIntoSendingResultDiagnosticEmitter::emit() { // Then emit the note with greater context. - SmallString<64> descriptiveKindStr; - { - llvm::raw_svector_ostream os(descriptiveKindStr); - isolatedValueIsolationRegionInfo.printForDiagnostics(os); - } + auto descriptiveKindStr = + isolatedValueIsolationRegionInfo.printForDiagnostics(getFunction()); // Grab the var name if we can find it. if (auto varName = VariableNameInferrer::inferName(srcOperand->get())) { @@ -2516,6 +2470,10 @@ struct NonSendableIsolationCrossingResultDiagnosticEmitter { : valueMap(valueMap), error(error), representative(valueMap.getRepresentative(error.returnValueElement)) {} + SILFunction *getFunction() const { + return error.op->getSourceInst()->getFunction(); + } + void emit(); ASTContext &getASTContext() const { @@ -2632,17 +2590,22 @@ void NonSendableIsolationCrossingResultDiagnosticEmitter::emit() { if (!isolationCrossing) return emitUnknownPatternError(); + auto calleeIsolationStr = SILIsolationInfo::printActorIsolationForDiagnostics( + getFunction(), isolationCrossing->getCalleeIsolation()); + auto callerIsolationStr = SILIsolationInfo::printActorIsolationForDiagnostics( + getFunction(), isolationCrossing->getCallerIsolation()); + auto type = getType(); if (getCalledDecl()) { - diagnoseError(error.op->getSourceInst(), diag::rbi_isolation_crossing_result, - type, isolationCrossing->getCalleeIsolation(), getCalledDecl(), - isolationCrossing->getCallerIsolation()) - .limitBehaviorIf(getBehaviorLimit()); + diagnoseError(error.op->getSourceInst(), + diag::rbi_isolation_crossing_result, type, calleeIsolationStr, + getCalledDecl(), callerIsolationStr) + .limitBehaviorIf(getBehaviorLimit()); } else { - diagnoseError(error.op->getSourceInst(), diag::rbi_isolation_crossing_result_no_decl, - type, isolationCrossing->getCalleeIsolation(), - isolationCrossing->getCallerIsolation()) - .limitBehaviorIf(getBehaviorLimit()); + diagnoseError(error.op->getSourceInst(), + diag::rbi_isolation_crossing_result_no_decl, type, + calleeIsolationStr, callerIsolationStr) + .limitBehaviorIf(getBehaviorLimit()); } if (type->is()) { diagnoseNote(error.op->getSourceInst(), diff --git a/lib/SILOptimizer/Utils/PartitionUtils.cpp b/lib/SILOptimizer/Utils/PartitionUtils.cpp index 4980743c20278..55a75e42f548c 100644 --- a/lib/SILOptimizer/Utils/PartitionUtils.cpp +++ b/lib/SILOptimizer/Utils/PartitionUtils.cpp @@ -46,7 +46,7 @@ void PartitionOpError::SentNeverSendableError::print( << " ID: %%" << sentElement << "\n" << " Rep: " << *info.getRepresentative(sentElement) << " Dynamic Isolation Region: "; - isolationRegionInfo.printForOneLineLogging(os); + isolationRegionInfo.printForOneLineLogging(info.getFunction(), os); os << '\n'; if (auto isolatedValue = isolationRegionInfo->maybeGetIsolatedValue()) { os << " Isolated Value: " << isolatedValue; @@ -90,7 +90,7 @@ void PartitionOpError::InOutSendingNotDisconnectedAtExitError::print( << " ID: %%" << inoutSendingElement << "\n" << " Rep: " << valueMap.getRepresentativeValue(inoutSendingElement) << " Dynamic Isolation Region: "; - isolationInfo.printForOneLineLogging(os); + isolationInfo.printForOneLineLogging(valueMap.getFunction(), os); os << '\n'; } diff --git a/lib/SILOptimizer/Utils/SILIsolationInfo.cpp b/lib/SILOptimizer/Utils/SILIsolationInfo.cpp index cfe3b918682ef..b4af1a75e28fc 100644 --- a/lib/SILOptimizer/Utils/SILIsolationInfo.cpp +++ b/lib/SILOptimizer/Utils/SILIsolationInfo.cpp @@ -447,6 +447,21 @@ SILIsolationInfo SILIsolationInfo::get(SILInstruction *inst) { return info; } + // See if our function apply site has an implicit isolated parameter. In + // such a case, we know that we have a caller inheriting isolated + // function. Return that this has disconnected isolation. + // + // DISCUSSION: The reason why we are doing this is that we already know that + // the AST is not going to label this as an isolation crossing point so we + // will only perform a merge. We want to just perform an isolation merge + // without adding additional isolation info. Otherwise, a nonisolated + // function that + if (auto paramInfo = fas.getSubstCalleeType()->maybeGetIsolatedParameter(); + paramInfo && paramInfo->hasOption(SILParameterInfo::ImplicitLeading) && + paramInfo->hasOption(SILParameterInfo::Isolated)) { + return SILIsolationInfo::getDisconnected(false /*unsafe nonisolated*/); + } + if (auto *isolatedOp = fas.getIsolatedArgumentOperandOrNullPtr()) { // First look through ActorInstance agnostic values so we can find the // type of the actual underlying actor (e.x.: copy_value, @@ -539,9 +554,8 @@ SILIsolationInfo SILIsolationInfo::get(SILInstruction *inst) { if (actorInstance) { if (auto actualIsolatedValue = ActorInstance::getForValue(actorInstance)) { - // See if we have a function parameter. In that case, we want to see - // if we have a function argument. In such a case, we need to use - // the right parameter and the var decl. + // See if we have a function parameter. In such a case, we need to + // use the right parameter and the var decl. if (auto *fArg = dyn_cast( actualIsolatedValue.getValue())) { if (auto info = @@ -924,6 +938,12 @@ SILIsolationInfo SILIsolationInfo::get(SILInstruction *inst) { /// Consider non-Sendable metatypes to be task-isolated, so they cannot cross /// into another isolation domain. if (auto *mi = dyn_cast(inst)) { + if (auto funcIsolation = mi->getFunction()->getActorIsolation(); + funcIsolation && funcIsolation->isCallerIsolationInheriting()) { + return SILIsolationInfo::getTaskIsolated(mi) + .withNonisolatedNonsendingTaskIsolated(true); + } + return SILIsolationInfo::getTaskIsolated(mi); } @@ -985,6 +1005,14 @@ SILIsolationInfo SILIsolationInfo::get(SILArgument *arg) { // handles isolated self and specifically marked isolated. if (auto *isolatedArg = llvm::cast_or_null( fArg->getFunction()->maybeGetIsolatedArgument())) { + // See if the function is nonisolated(nonsending). In such a case, return + // task isolated. + if (auto funcIsolation = fArg->getFunction()->getActorIsolation(); + funcIsolation && funcIsolation->isCallerIsolationInheriting()) { + return SILIsolationInfo::getTaskIsolated(fArg) + .withNonisolatedNonsendingTaskIsolated(true); + } + auto astType = isolatedArg->getType().getASTType(); if (astType->lookThroughAllOptionalTypes()->getAnyActor()) { return SILIsolationInfo::getActorInstanceIsolated(fArg, isolatedArg); @@ -1216,7 +1244,41 @@ void SILIsolationInfo::printOptions(llvm::raw_ostream &os) const { llvm::interleave(data, os, ", "); } -void SILIsolationInfo::print(llvm::raw_ostream &os) const { +StringRef SILIsolationInfo::printActorIsolationForDiagnostics( + SILFunction *fn, ActorIsolation iso, StringRef openingQuotationMark, + bool asNoun) { + SmallString<64> string; + { + llvm::raw_svector_ostream os(string); + printActorIsolationForDiagnostics(fn, iso, os, openingQuotationMark, + asNoun); + } + + return fn->getASTContext().getIdentifier(string).str(); +} + +void SILIsolationInfo::printActorIsolationForDiagnostics( + SILFunction *fn, ActorIsolation iso, llvm::raw_ostream &os, + StringRef openingQuotationMark, bool asNoun) { + // If we have NonisolatedNonsendingByDefault enabled, we need to return + // @concurrent for nonisolated and nonisolated for caller isolation inherited. + if (fn->isAsync() && fn->getASTContext().LangOpts.hasFeature( + Feature::NonisolatedNonsendingByDefault)) { + if (iso.isCallerIsolationInheriting()) { + os << "nonisolated"; + return; + } + + if (iso.isNonisolated()) { + os << "@concurrent"; + return; + } + } + + return iso.printForDiagnostics(os, openingQuotationMark, asNoun); +} + +void SILIsolationInfo::print(SILFunction *fn, llvm::raw_ostream &os) const { switch (Kind(*this)) { case Unknown: os << "unknown"; @@ -1263,7 +1325,7 @@ void SILIsolationInfo::print(llvm::raw_ostream &os) const { } } - getActorIsolation().printForDiagnostics(os); + printActorIsolationForDiagnostics(fn, getActorIsolation(), os); printOptions(os); return; case Task: @@ -1334,6 +1396,7 @@ bool SILIsolationInfo::isEqual(const SILIsolationInfo &other) const { void SILIsolationInfo::Profile(llvm::FoldingSetNodeID &id) const { id.AddInteger(getKind()); + id.AddInteger(getOptions().toRaw()); switch (getKind()) { case Unknown: case Disconnected: @@ -1350,7 +1413,18 @@ void SILIsolationInfo::Profile(llvm::FoldingSetNodeID &id) const { } } -void SILIsolationInfo::printForDiagnostics(llvm::raw_ostream &os) const { +StringRef SILIsolationInfo::printForDiagnostics(SILFunction *fn) const { + SmallString<64> string; + { + llvm::raw_svector_ostream os(string); + printForDiagnostics(fn, os); + } + + return fn->getASTContext().getIdentifier(string).str(); +} + +void SILIsolationInfo::printForDiagnostics(SILFunction *fn, + llvm::raw_ostream &os) const { switch (Kind(*this)) { case Unknown: llvm::report_fatal_error("Printing unknown for diagnostics?!"); @@ -1385,15 +1459,41 @@ void SILIsolationInfo::printForDiagnostics(llvm::raw_ostream &os) const { } } - getActorIsolation().printForDiagnostics(os); + printActorIsolationForDiagnostics(fn, getActorIsolation(), os); return; case Task: + if (fn->isAsync() && fn->getASTContext().LangOpts.hasFeature( + Feature::NonisolatedNonsendingByDefault)) { + if (isNonisolatedNonsendingTaskIsolated()) { + os << "task-isolated"; + return; + } + os << "@concurrent task-isolated"; + return; + } + + if (isNonisolatedNonsendingTaskIsolated()) { + os << "nonisolated(nonsending) task-isolated"; + return; + } + os << "task-isolated"; return; } } -void SILIsolationInfo::printForCodeDiagnostic(llvm::raw_ostream &os) const { +StringRef SILIsolationInfo::printForCodeDiagnostic(SILFunction *fn) const { + SmallString<64> string; + { + llvm::raw_svector_ostream os(string); + printForCodeDiagnostic(fn, os); + } + + return fn->getASTContext().getIdentifier(string).str(); +} + +void SILIsolationInfo::printForCodeDiagnostic(SILFunction *fn, + llvm::raw_ostream &os) const { switch (Kind(*this)) { case Unknown: llvm::report_fatal_error("Printing unknown for code diagnostic?!"); @@ -1428,7 +1528,7 @@ void SILIsolationInfo::printForCodeDiagnostic(llvm::raw_ostream &os) const { } } - getActorIsolation().printForDiagnostics(os); + printActorIsolationForDiagnostics(fn, getActorIsolation(), os); os << " code"; return; case Task: @@ -1437,7 +1537,8 @@ void SILIsolationInfo::printForCodeDiagnostic(llvm::raw_ostream &os) const { } } -void SILIsolationInfo::printForOneLineLogging(llvm::raw_ostream &os) const { +void SILIsolationInfo::printForOneLineLogging(SILFunction *fn, + llvm::raw_ostream &os) const { switch (Kind(*this)) { case Unknown: os << "unknown"; @@ -1477,7 +1578,7 @@ void SILIsolationInfo::printForOneLineLogging(llvm::raw_ostream &os) const { } } - getActorIsolation().printForDiagnostics(os); + printActorIsolationForDiagnostics(fn, getActorIsolation(), os); printOptions(os); return; case Task: @@ -1606,8 +1707,13 @@ std::optional SILDynamicMergedIsolationInfo::merge(SILIsolationInfo other) const { // If we are greater than the other kind, then we are further along the // lattice. We ignore the change. - if (unsigned(innerInfo.getKind() > unsigned(other.getKind()))) + // + // NOTE: If we are further along, then we both cannot be task isolated. In + // such a case, we are the only potential thing that can be + // nonisolated(unsafe)... so we do not need to try to propagate. + if (unsigned(innerInfo.getKind() > unsigned(other.getKind()))) { return {*this}; + } // If we are both actor isolated... if (innerInfo.isActorIsolated() && other.isActorIsolated()) { @@ -1642,6 +1748,21 @@ SILDynamicMergedIsolationInfo::merge(SILIsolationInfo other) const { return {other.withUnsafeNonIsolated(false)}; } + // We know that we are either the same as other or other is further along. If + // other is further along, it is the only thing that can propagate the task + // isolated bit. So we do not need to do anything. If we are equal though, we + // may need to propagate the bit. This ensures that when we emit a diagnostic + // we appropriately say potentially actor isolated code instead of code in the + // current task. + // + // TODO: We should really represent this as a separate isolation info + // kind... but that would be a larger change than we want for 6.2. + if (innerInfo.isTaskIsolated() && other.isTaskIsolated()) { + if (innerInfo.isNonisolatedNonsendingTaskIsolated() || + other.isNonisolatedNonsendingTaskIsolated()) + return other.withNonisolatedNonsendingTaskIsolated(true); + } + // Otherwise, just return other. return {other}; } @@ -1684,7 +1805,8 @@ static FunctionTest SILIsolationInfo::get(value); llvm::outs() << "Input Value: " << *value; llvm::outs() << "Isolation: "; - info.printForOneLineLogging(llvm::outs()); + info.printForOneLineLogging(&function, + llvm::outs()); llvm::outs() << "\n"; }); @@ -1704,13 +1826,13 @@ static FunctionTest IsolationMergeTest( mergedInfo = mergedInfo->merge(secondValueInfo); llvm::outs() << "First Value: " << *firstValue; llvm::outs() << "First Isolation: "; - firstValueInfo.printForOneLineLogging(llvm::outs()); + firstValueInfo.printForOneLineLogging(&function, llvm::outs()); llvm::outs() << "\nSecond Value: " << *secondValue; llvm::outs() << "Second Isolation: "; - secondValueInfo.printForOneLineLogging(llvm::outs()); + secondValueInfo.printForOneLineLogging(&function, llvm::outs()); llvm::outs() << "\nMerged Isolation: "; if (mergedInfo) { - mergedInfo->printForOneLineLogging(llvm::outs()); + mergedInfo->printForOneLineLogging(&function, llvm::outs()); } else { llvm::outs() << "Merge failure!"; } diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index a214f7377bea9..5fcbf38a3a07d 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -7861,23 +7861,6 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType, } } - // If we have a ClosureExpr, then we can safely propagate the - // 'nonisolated(nonsending)' isolation if it's not explicitly - // marked as `@concurrent`. - if (toEI.getIsolation().isNonIsolatedCaller() && - (fromEI.getIsolation().isNonIsolated() && - !isClosureMarkedAsConcurrent(expr))) { - auto newFromFuncType = fromFunc->withIsolation( - FunctionTypeIsolation::forNonIsolatedCaller()); - if (applyTypeToClosureExpr(cs, expr, newFromFuncType)) { - fromFunc = newFromFuncType->castTo(); - // Propagating 'nonisolated(nonsending)' might have satisfied the entire - // conversion. If so, we're done, otherwise keep converting. - if (fromFunc->isEqual(toType)) - return expr; - } - } - if (ctx.LangOpts.isDynamicActorIsolationCheckingEnabled()) { // Passing a synchronous global actor-isolated function value and // parameter that expects a synchronous non-isolated function type could diff --git a/lib/Sema/TypeCheckConcurrency.cpp b/lib/Sema/TypeCheckConcurrency.cpp index 97a0927f7c843..2ae325f28b30e 100644 --- a/lib/Sema/TypeCheckConcurrency.cpp +++ b/lib/Sema/TypeCheckConcurrency.cpp @@ -4067,6 +4067,10 @@ namespace { Expr *argForIsolatedParam = nullptr; auto calleeDecl = apply->getCalledValue(/*skipFunctionConversions=*/true); + if (calleeDecl && + calleeDecl->getAttrs().hasAttribute()) + return false; + auto fnTypeIsolation = fnType->getIsolation(); if (fnTypeIsolation.isGlobalActor()) { // If the function type is global-actor-qualified, determine whether @@ -4112,10 +4116,6 @@ namespace { calleeDecl = memberRef->first.getDecl(); argForIsolatedParam = selfApplyFn->getBase(); } - } else if (calleeDecl && - calleeDecl->getAttrs() - .hasAttribute()) { - return false; } // Check for isolated parameters. @@ -4166,11 +4166,25 @@ namespace { break; } - // If we're calling an async function that's nonisolated, and we're in - // an isolated context, then we're exiting the actor context. - if (mayExitToNonisolated && fnType->isAsync() && - getContextIsolation().isActorIsolated()) - unsatisfiedIsolation = ActorIsolation::forNonisolated(/*unsafe=*/false); + // If we're calling an async function that's nonisolated, and we're in an + // isolated context, then we're exiting the actor context unless we have + // nonisolated(nonsending) isolation. + // + // NOTE: We do not check fnTypeIsolation since that is the AST level + // actual isolation which does not have nonisolated(nonsending) added to + // it yet. Instead, we want the direct callee including casts since those + // casts is what would add the nonisolated(nonsending) bit to the function + // type isolation. + if (mayExitToNonisolated && fnType->isAsync()) { + if (getContextIsolation().isActorIsolated() && + !fnTypeIsolation.isNonIsolatedCaller()) + unsatisfiedIsolation = + ActorIsolation::forNonisolated(/*unsafe=*/false); + else if (getContextIsolation().isCallerIsolationInheriting() && + fnTypeIsolation.isNonIsolated()) + unsatisfiedIsolation = + ActorIsolation::forNonisolated(/*unsafe=*/false); + } // If there was no unsatisfied actor isolation, we're done. if (!unsatisfiedIsolation) @@ -4973,8 +4987,33 @@ ActorIsolation ActorIsolationChecker::determineClosureIsolation( closure->getParent(), getClosureActorIsolation); preconcurrency |= parentIsolation.preconcurrency(); - return computeClosureIsolationFromParent(closure, parentIsolation, - checkIsolatedCapture); + auto normalIsolation = computeClosureIsolationFromParent( + closure, parentIsolation, checkIsolatedCapture); + + // The solver has to be conservative and produce a conversion to + // `nonisolated(nonsending)` because at solution application time + // we don't yet know whether there are any captures which would + // make closure isolated. + // + // At this point we know that closure is not explicitly annotated with + // global actor, nonisolated/@concurrent attributes and doesn't have + // isolated parameters. If our closure is nonisolated and we have a + // conversion to nonisolated(nonsending), then we should respect that. + if (auto *explicitClosure = dyn_cast(closure); + !normalIsolation.isGlobalActor()) { + if (auto *fce = + dyn_cast_or_null(Parent.getAsExpr())) { + auto expectedIsolation = + fce->getType()->castTo()->getIsolation(); + if (expectedIsolation.isNonIsolatedCaller()) { + auto captureInfo = explicitClosure->getCaptureInfo(); + if (!captureInfo.getIsolatedParamCapture()) + return ActorIsolation::forCallerIsolationInheriting(); + } + } + } + + return normalIsolation; }(); // Apply computed preconcurrency. @@ -8129,12 +8168,14 @@ ActorReferenceResult ActorReferenceResult::forReference( // When the declaration is not actor-isolated, it can always be accessed // directly. if (!declIsolation.isActorIsolated()) { + if (declRef.getDecl()->getAttrs().hasAttribute()) + return forSameConcurrencyDomain(declIsolation, options); + // If the declaration is asynchronous and we are in an actor-isolated - // context (of any kind), then we exit the actor to the nonisolated context. - if (decl->isAsync() && contextIsolation.isActorIsolated() && - !declRef.getDecl() - ->getAttrs() - .hasAttribute()) + // context (of any kind) or it is a caller isolation inheriting, then + // we exit the actor to the nonisolated context. + if (decl->isAsync() && (contextIsolation.isActorIsolated() || + contextIsolation.isCallerIsolationInheriting())) return forExitsActorToNonisolated(contextIsolation, options); // Otherwise, we stay in the same concurrency domain, whether on an actor diff --git a/test/ClangImporter/Inputs/regionbasedisolation.h b/test/ClangImporter/Inputs/regionbasedisolation.h index 7852358ca5a3e..6385570570d3e 100644 --- a/test/ClangImporter/Inputs/regionbasedisolation.h +++ b/test/ClangImporter/Inputs/regionbasedisolation.h @@ -13,6 +13,9 @@ NS_ASSUME_NONNULL_BEGIN (void (^)(NSArray *_Nullable, NSError *_Nullable))completionHandler; +- (void)useValue:(id)object + withCompletionHandler:(void (^)(NSObject *_Nullable))completionHandler; + @end NS_ASSUME_NONNULL_END diff --git a/test/ClangImporter/regionbasedisolation.swift b/test/ClangImporter/regionbasedisolation.swift index 63a2364dafbb2..4f86aedd320a0 100644 --- a/test/ClangImporter/regionbasedisolation.swift +++ b/test/ClangImporter/regionbasedisolation.swift @@ -1,7 +1,9 @@ -// RUN: %target-swift-frontend %s -import-objc-header %S/Inputs/regionbasedisolation.h -verify -c -swift-version 6 +// RUN: %target-swift-frontend %s -import-objc-header %S/Inputs/regionbasedisolation.h -verify -verify-additional-prefix ni- -c -swift-version 6 +// RUN: %target-swift-frontend %s -import-objc-header %S/Inputs/regionbasedisolation.h -verify -verify-additional-prefix ni-ns- -c -swift-version 6 -enable-upcoming-feature NonisolatedNonsendingByDefault // RUN: %target-swift-frontend %s -import-objc-header %S/Inputs/regionbasedisolation.h -emit-silgen -swift-version 6 | %FileCheck %s // REQUIRES: objc_interop +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault extension ObjCObject { // CHECK-LABEL: sil hidden [ossa] @$sSo10ObjCObjectC20regionbasedisolationE11sendObjectsSaySo8NSObjectCGyYaKF : $@convention(method) @async (@guaranteed ObjCObject) -> (@sil_sending @owned Array, @error any Error) { @@ -123,3 +125,40 @@ extension ObjCObject { try await loadObjects2() } // expected-error {{task or actor isolated value cannot be sent}} } + +@concurrent func useValueConcurrently(_ t: T) async {} +@MainActor func useValueMainActor(_ t: T) async {} +nonisolated(nonsending) func useValueNonIsolatedNonSending(_ t: T) async {} + +@MainActor func testMainActorMerging(_ y: NSObject) async { + let x = ObjCObject() + await x.useValue(y) + await useValueConcurrently(x) // expected-error {{sending 'x' risks causing data races}} + // expected-ni-note @-1 {{sending main actor-isolated 'x' to nonisolated global function 'useValueConcurrently' risks causing data races between nonisolated and main actor-isolated uses}} + // expected-ni-ns-note @-2 {{sending main actor-isolated 'x' to @concurrent global function 'useValueConcurrently' risks causing data races between @concurrent and main actor-isolated uses}} +} + +func testTaskLocal(_ y: NSObject) async { + let x = ObjCObject() + await x.useValue(y) + await useValueConcurrently(x) // expected-ni-ns-error {{sending 'x' risks causing data races}} + // expected-ni-ns-note @-1 {{sending task-isolated 'x' to @concurrent global function 'useValueConcurrently' risks causing data races between @concurrent and task-isolated uses}} + + // This is not safe since we merge x into y's region making x task + // isolated. We then try to send it to a main actor function. + await useValueMainActor(x) // expected-error {{sending 'x' risks causing data races}} + // expected-note @-1 {{sending task-isolated 'x' to main actor-isolated global function 'useValueMainActor' risks causing data races between main actor-isolated and task-isolated uses}} +} + +actor MyActor { + var field = NSObject() + + // This is safe since x.useValue is going to be nonisolated(nonsending) so we + // are going to merge x into the actor. And useValueNonIsolatedNonSending + // inherits from the context. + func test() async { + let x = ObjCObject() + await x.useValue(field) + await useValueNonIsolatedNonSending(x) + } +} diff --git a/test/Concurrency/attr_execution/attr_execution.swift b/test/Concurrency/attr_execution/attr_execution.swift index 93702c1c8aacb..c9f855cb770c9 100644 --- a/test/Concurrency/attr_execution/attr_execution.swift +++ b/test/Concurrency/attr_execution/attr_execution.swift @@ -18,7 +18,7 @@ func callerTest() async {} struct Test { // CHECK-LABEL: // closure #1 in variable initialization expression of Test.x // CHECK: // Isolation: caller_isolation_inheriting - // CHECK: sil private [ossa] @$s14attr_execution4TestV1xyyYaYCcvpfiyyYaYCcfU_ : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional) -> () + // CHECK: sil private [ossa] @$s14attr_execution4TestV1xyyYaYCcvpfiyyYacfU_ : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional) -> () var x: () async -> Void = {} // CHECK-LABEL: // Test.test() @@ -67,7 +67,7 @@ func takesClosure(fn: () async -> Void) { } // CHECK-LABEL: sil hidden [ossa] @$s14attr_execution11testClosureyyF : $@convention(thin) () -> () -// CHECK: [[CLOSURE:%.*]] = function_ref @$s14attr_execution11testClosureyyFyyYaYCXEfU_ : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional) -> () +// CHECK: [[CLOSURE:%.*]] = function_ref @$s14attr_execution11testClosureyyFyyYaXEfU_ : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional) -> () // CHECK: [[THUNKED_CLOSURE:%.*]] = thin_to_thick_function %0 to $@noescape @async @callee_guaranteed (@sil_isolated @sil_implicit_leading_param @guaranteed Optional) -> () // CHECK: [[TAKES_CLOSURE:%.*]] = function_ref @$s14attr_execution12takesClosure2fnyyyYaYCXE_tF : $@convention(thin) (@guaranteed @noescape @async @callee_guaranteed (@sil_isolated @sil_implicit_leading_param @guaranteed Optional) -> ()) -> () // CHECK: apply [[TAKES_CLOSURE]]([[THUNKED_CLOSURE]]) @@ -75,7 +75,7 @@ func takesClosure(fn: () async -> Void) { // CHECK-LABEL: // closure #1 in testClosure() // CHECK: // Isolation: caller_isolation_inheriting -// CHECK: sil private [ossa] @$s14attr_execution11testClosureyyFyyYaYCXEfU_ : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional) -> () +// CHECK: sil private [ossa] @$s14attr_execution11testClosureyyFyyYaXEfU_ : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional) -> () func testClosure() { takesClosure { } diff --git a/test/Concurrency/attr_execution/conversions_silgen.swift b/test/Concurrency/attr_execution/conversions_silgen.swift index 7b97a59fc57e5..2271c686ed172 100644 --- a/test/Concurrency/attr_execution/conversions_silgen.swift +++ b/test/Concurrency/attr_execution/conversions_silgen.swift @@ -421,7 +421,7 @@ func conversionsFromSyncToAsync(_ x: @escaping @Sendable (NonSendableKlass) -> V } func testThatClosuresAssumeIsolation(fn: inout nonisolated(nonsending) (Int) async -> Void) { - // CHECK-LABEL: sil private [ossa] @$s21attr_execution_silgen31testThatClosuresAssumeIsolation2fnyySiYaYCcz_tFyyYaYCcfU_ : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional) -> () + // CHECK-LABEL: sil private [ossa] @$s21attr_execution_silgen31testThatClosuresAssumeIsolation2fnyySiYaYCcz_tFyyYacfU_ : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional) -> () { // CHECK: bb0([[EXECUTOR:%.*]] : @guaranteed $Optional): // CHECK: hop_to_executor [[EXECUTOR]] let _: nonisolated(nonsending) () async -> Void = { @@ -430,7 +430,7 @@ func testThatClosuresAssumeIsolation(fn: inout nonisolated(nonsending) (Int) asy func testParam(_: nonisolated(nonsending) () async throws -> Void) {} - // CHECK-LABEL: sil private [ossa] @$s21attr_execution_silgen31testThatClosuresAssumeIsolation2fnyySiYaYCcz_tFyyYaYCXEfU0_ : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional) -> @error any Error + // CHECK-LABEL: sil private [ossa] @$s21attr_execution_silgen31testThatClosuresAssumeIsolation2fnyySiYaYCcz_tFyyYaXEfU0_ : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional) -> () { // CHECK: bb0([[EXECUTOR:%.*]] : @guaranteed $Optional): // CHECK: hop_to_executor [[EXECUTOR]] testParam { 42 } @@ -440,7 +440,7 @@ func testThatClosuresAssumeIsolation(fn: inout nonisolated(nonsending) (Int) asy // CHECK: hop_to_executor [[GENERIC_EXECUTOR]] testParam { @concurrent in 42 } - // CHECK-LABEL: sil private [ossa] @$s21attr_execution_silgen31testThatClosuresAssumeIsolation2fnyySiYaYCcz_tFySiYaYCcfU2_ : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional, Int) -> () + // CHECK-LABEL: sil private [ossa] @$s21attr_execution_silgen31testThatClosuresAssumeIsolation2fnyySiYaYCcz_tFySiYacfU2_ : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional, Int) -> () { // CHECK: bb0([[EXECUTOR:%.*]] : @guaranteed $Optional, %1 : $Int): // CHECK: hop_to_executor [[EXECUTOR]] fn = { _ in } diff --git a/test/Concurrency/concurrent_value_checking.swift b/test/Concurrency/concurrent_value_checking.swift index 0738d4ea0dd0a..7dc503268a0d3 100644 --- a/test/Concurrency/concurrent_value_checking.swift +++ b/test/Concurrency/concurrent_value_checking.swift @@ -1,9 +1,11 @@ // RUN: %target-swift-frontend -target %target-swift-5.1-abi-triple -strict-concurrency=complete -parse-as-library %s -emit-sil -o /dev/null -verify -DALLOW_TYPECHECKER_ERRORS -verify-additional-prefix typechecker- -verify-additional-prefix tns-allow-typechecker- -// RUN: %target-swift-frontend -target %target-swift-5.1-abi-triple -strict-concurrency=complete -parse-as-library %s -emit-sil -o /dev/null -verify -verify-additional-prefix tns- +// RUN: %target-swift-frontend -target %target-swift-5.1-abi-triple -strict-concurrency=complete -parse-as-library %s -emit-sil -o /dev/null -verify -verify-additional-prefix tns-ni- -verify-additional-prefix tns- +// RUN: %target-swift-frontend -target %target-swift-5.1-abi-triple -strict-concurrency=complete -parse-as-library %s -emit-sil -o /dev/null -verify -verify-additional-prefix tns-ni-ns- -verify-additional-prefix tns- -enable-upcoming-feature NonisolatedNonsendingByDefault // REQUIRES: concurrency // REQUIRES: asserts +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault class NotConcurrent { } // expected-note 12{{class 'NotConcurrent' does not conform to the 'Sendable' protocol}} // expected-tns-allow-typechecker-note @-1 {{class 'NotConcurrent' does not conform to the 'Sendable' protocol}} diff --git a/test/Concurrency/concurrent_value_checking_objc.swift b/test/Concurrency/concurrent_value_checking_objc.swift index a08c6a3ebb2bc..5b16ce46233de 100644 --- a/test/Concurrency/concurrent_value_checking_objc.swift +++ b/test/Concurrency/concurrent_value_checking_objc.swift @@ -1,8 +1,10 @@ -// RUN: %target-swift-frontend -target %target-swift-5.1-abi-triple -strict-concurrency=complete %s -emit-sil -o /dev/null -verify +// RUN: %target-swift-frontend -target %target-swift-5.1-abi-triple -strict-concurrency=complete %s -emit-sil -o /dev/null -verify -verify-additional-prefix ni- +// RUN: %target-swift-frontend -target %target-swift-5.1-abi-triple -strict-concurrency=complete %s -emit-sil -o /dev/null -verify -verify-additional-prefix ni-ns- -enable-upcoming-feature NonisolatedNonsendingByDefault // REQUIRES: concurrency // REQUIRES: objc_interop // REQUIRES: asserts +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault import Foundation diff --git a/test/Concurrency/nonisolated_inherits_isolation.swift b/test/Concurrency/nonisolated_inherits_isolation.swift index ec1e6d8211d84..82dc816633761 100644 --- a/test/Concurrency/nonisolated_inherits_isolation.swift +++ b/test/Concurrency/nonisolated_inherits_isolation.swift @@ -13,7 +13,12 @@ // Declarations // ////////////////// -class NonSendableKlass {} +class NonSendableKlass { + func unspecifiedCaller() async {} + nonisolated func nonisolatedCaller() async {} + nonisolated(nonsending) func nonisolatedNonSendingCaller() async {} + @concurrent func concurrentCaller() async {} +} nonisolated class NonIsolatedNonSendableKlass { func unspecifiedMethod() async {} @@ -24,6 +29,8 @@ func unspecifiedSyncUse(_ t: T) {} func unspecifiedAsyncUse(_ t: T) async {} nonisolated func nonisolatedSyncUse(_ t: T) {} nonisolated func nonisolatedAsyncUse(_ t: T) async {} +nonisolated(nonsending) func nonisolatedNonSendingAsyncUse(_ t: T) async {} +@concurrent func concurrentAsyncUse(_ t: T) async {} func unspecifiedSyncUseWithResult(_ t: T) -> T { t } func unspecifiedAsyncUseWithResult(_ t: T) async -> T { t } @@ -34,6 +41,8 @@ func unspecifiedSyncResult() -> NonSendableKlass { fatalError() } func unspecifiedAsyncResult() async -> NonSendableKlass { fatalError() } nonisolated func nonisolatedSyncResult() -> NonSendableKlass { fatalError() } nonisolated func nonisolatedAsyncResult() async -> NonSendableKlass { fatalError() } +func sendingParameter(_ t: sending T) async {} +func useValue(_ t: T) {} @MainActor func sendToMain(_ t: T) async {} @@ -49,6 +58,13 @@ struct CustomActor { @CustomActor func sendToCustom(_ t: T) async {} +@MainActor +final class MainActorKlass { + var ns = NonSendableKlass() + + func useValueAsync(_ x: NonSendableKlass) async {} +} + /////////// // Tests // /////////// @@ -90,22 +106,17 @@ actor ActorTest { await sendToMain(x1) let x2 = await unspecifiedAsyncResult() - await sendToMain(x2) // expected-enabled-error {{sending 'x2' risks causing data races}} - // expected-enabled-note @-1 {{sending 'self'-isolated 'x2' to main actor-isolated global function 'sendToMain' risks causing data races between main actor-isolated and 'self'-isolated uses}} + await sendToMain(x2) let x3 = nonisolatedSyncResult() await sendToMain(x3) let x4 = await nonisolatedAsyncResult() - await sendToMain(x4) // expected-enabled-error {{sending 'x4' risks causing data races}} - // expected-enabled-note @-1 {{sending 'self'-isolated 'x4' to main actor-isolated global function 'sendToMain' risks causing data races between main actor-isolated and 'self'-isolated uses}} + await sendToMain(x4) } } -@MainActor -class MainActorKlass { - var ns = NonSendableKlass() - +extension MainActorKlass { func callNonIsolatedWithParam() async { unspecifiedSyncUse(ns) await unspecifiedAsyncUse(ns) // expected-disabled-error {{sending 'self.ns' risks causing data races}} @@ -141,15 +152,13 @@ class MainActorKlass { await sendToCustom(x1) let x2 = await unspecifiedAsyncResult() - await sendToCustom(x2) // expected-enabled-error {{sending 'x2' risks causing data races}} - // expected-enabled-note @-1 {{sending main actor-isolated 'x2' to global actor 'CustomActor'-isolated global function 'sendToCustom' risks causing data races between global actor 'CustomActor'-isolated and main actor-isolated uses}} + await sendToCustom(x2) let x3 = nonisolatedSyncResult() await sendToCustom(x3) let x4 = await nonisolatedAsyncResult() - await sendToCustom(x4) // expected-enabled-error {{sending 'x4' risks causing data races}} - // expected-enabled-note @-1 {{sending main actor-isolated 'x4' to global actor 'CustomActor'-isolated global function 'sendToCustom' risks causing data races between global actor 'CustomActor'-isolated and main actor-isolated uses}} + await sendToCustom(x4) } } @@ -166,3 +175,171 @@ func validateNonisolatedOnClassMeansCallerIsolationInheritingOnFuncDecl( await c.nonisolatedMethod() // expected-disabled-error {{sending 'c' risks causing data races}} // expected-disabled-note @-1 {{sending main actor-isolated 'c' to nonisolated instance method 'nonisolatedMethod()' risks causing data races between nonisolated and main actor-isolated uses}} } + +// Shouldn't get an error here since we are not using after we send to main. +func nonisolatedCallingNonIsolated() async { + let c = NonSendableKlass() + + await unspecifiedAsyncUse(c) + await unspecifiedAsyncUse(c) + + await sendToMain(c) +} + +func nonisolatedCallingNonIsolated2() async { + let c = NonSendableKlass() + + await unspecifiedAsyncUse(c) + await unspecifiedAsyncUse(c) + + await sendToMain(c) // expected-error {{sending 'c' risks causing data races}} + // expected-note @-1 {{sending 'c' to main actor-isolated global function 'sendToMain' risks causing data races between main actor-isolated and local nonisolated uses}} + + await unspecifiedAsyncUse(c) // expected-note {{access can happen concurrently}} +} + +// We should emit an error here despite the function context being @MainActor. +@MainActor +func sendingWithMainActor() async { + let c = NonSendableKlass() + await sendingParameter(c) // expected-error {{sending 'c' risks causing data races}} + // expected-note @-1 {{'c' used after being passed as a 'sending' parameter}} + useValue(c) // expected-note {{access can happen concurrently}} +} + +// We should emit an error here despite the function context have an explicit +// isolated parameter. +func sendingWithIsolatedParam(_ a: isolated Optional) async { + let c = NonSendableKlass() + await sendingParameter(c) // expected-error {{sending 'c' risks causing data races}} + // expected-note @-1 {{'c' used after being passed as a 'sending' parameter}} + useValue(c) // expected-note {{access can happen concurrently}} +} + +// This errors only when disabled since the first time we call +// unspecifiedAsyncUse we have a disconnected value and the second time we have +// a value in a main actor isolated region and the unspecifiedAsyncUse runs on +// the main actor. +// +// TODO: This doesn't error if we have a non-final class because of a known bug +// where we infer isolation wrong for non-final class setters. That is why +// MainActorKlass is made final so we can test this appropriately. +@MainActor +func testUnrolledLoop(_ a: MainActorKlass) async { + let k = NonSendableKlass() + await unspecifiedAsyncUse(k) + a.ns = k + await unspecifiedAsyncUse(k) // expected-disabled-error {{sending 'k' risks causing data races}} + // expected-disabled-note @-1 {{sending main actor-isolated 'k' to nonisolated global function 'unspecifiedAsyncUse' risks causing data races between nonisolated and main actor-isolated uses}} +} + +// We emit an error in both modes since we are now in an @MainActor isolated +// function. +func testUnrolledLoop2(_ a: MainActorKlass) async { + let k = NonSendableKlass() + await unspecifiedAsyncUse(k) + await a.useValueAsync(k) // expected-error {{sending 'k' risks causing data races}} + // expected-note @-1 {{sending 'k' to main actor-isolated instance method 'useValueAsync' risks causing data races between main actor-isolated and local nonisolated uses}} + await unspecifiedAsyncUse(k) // expected-note {{access can happen concurrently}} +} + +func testUnrolledLoopWithAsyncLet(_ a: MainActorKlass) async { + let k = NonSendableKlass() + await unspecifiedAsyncUse(k) + // This is valid since our valid is disconnected here. + async let value: () = await unspecifiedAsyncUse(k) + _ = await value + + await a.useValueAsync(k) // expected-error {{sending 'k' risks causing data races}} + // expected-note @-1 {{sending 'k' to main actor-isolated instance method 'useValueAsync' risks causing data races between main actor-isolated and local nonisolated uses}} + async let value2: () = await unspecifiedAsyncUse(k) // expected-note {{access can happen concurrently}} + _ = await value2 +} + +@MainActor +func testUnrolledLoopWithAsyncLet2(_ a: MainActorKlass) async { + let k = NonSendableKlass() + await unspecifiedAsyncUse(k) + // This is valid since our valid is disconnected here. + async let value: () = await unspecifiedAsyncUse(k) + _ = await value + + await a.useValueAsync(k) + async let value2: () = await unspecifiedAsyncUse(k) // expected-error {{sending 'k' risks causing data races}} + // expected-note @-1 {{sending main actor-isolated 'k' into async let risks causing data races between nonisolated and main actor-isolated uses}} + _ = await value2 +} + +@MainActor +func testUnrolledLoopWithAsyncLet3(_ a: MainActorKlass) async { + let k = NonSendableKlass() + await unspecifiedAsyncUse(k) + // This is valid since our valid is disconnected here. + async let value: () = await unspecifiedAsyncUse(k) + _ = await value + + await a.useValueAsync(k) + async let value2: () = await sendToMain(k) // expected-error {{sending 'k' risks causing data races}} + // expected-note @-1 {{sending main actor-isolated 'k' into async let risks causing data races between nonisolated and main actor-isolated uses}} + _ = await value2 +} + +func unspecifiedCallingVariousNonisolated(_ x: NonSendableKlass) async { + await x.unspecifiedCaller() + await x.nonisolatedCaller() + await x.nonisolatedNonSendingCaller() + await x.concurrentCaller() // expected-enabled-error {{sending 'x' risks causing data races}} + // expected-enabled-note @-1 {{sending task-isolated 'x' to @concurrent instance method 'concurrentCaller()' risks causing data races between @concurrent and task-isolated uses}} + + await unspecifiedAsyncUse(x) + await nonisolatedAsyncUse(x) + await nonisolatedNonSendingAsyncUse(x) + await concurrentAsyncUse(x) // expected-enabled-error {{sending 'x' risks causing data races}} + // expected-enabled-note @-1 {{sending task-isolated 'x' to @concurrent global function 'concurrentAsyncUse' risks causing data races between @concurrent and task-isolated uses}} +} + +nonisolated func nonisolatedCallingVariousNonisolated(_ x: NonSendableKlass) async { + await x.unspecifiedCaller() + await x.nonisolatedCaller() + await x.nonisolatedNonSendingCaller() + await x.concurrentCaller() // expected-enabled-error {{sending 'x' risks causing data races}} + // expected-enabled-note @-1 {{sending task-isolated 'x' to @concurrent instance method 'concurrentCaller()' risks causing data races between @concurrent and task-isolated uses}} + + await unspecifiedAsyncUse(x) + await nonisolatedAsyncUse(x) + await nonisolatedNonSendingAsyncUse(x) + await concurrentAsyncUse(x) // expected-enabled-error {{sending 'x' risks causing data races}} + // expected-enabled-note @-1 {{sending task-isolated 'x' to @concurrent global function 'concurrentAsyncUse' risks causing data races between @concurrent and task-isolated uses}} +} + +nonisolated(nonsending) func nonisolatedNonSendingCallingVariousNonisolated(_ x: NonSendableKlass) async { + await x.unspecifiedCaller() // expected-disabled-error {{sending 'x' risks causing data races}} + // expected-disabled-note @-1 {{sending nonisolated(nonsending) task-isolated 'x' to nonisolated instance method 'unspecifiedCaller()' risks causing data races between nonisolated and nonisolated(nonsending) task-isolated uses}} + await x.nonisolatedCaller() // expected-disabled-error {{sending 'x' risks causing data races}} + // expected-disabled-note @-1 {{sending nonisolated(nonsending) task-isolated 'x' to nonisolated instance method 'nonisolatedCaller()' risks causing data races between nonisolated and nonisolated(nonsending) task-isolated uses}} + await x.nonisolatedNonSendingCaller() + await x.concurrentCaller() // expected-error {{sending 'x' risks causing data races}} + // expected-disabled-note @-1 {{sending nonisolated(nonsending) task-isolated 'x' to nonisolated instance method 'concurrentCaller()' risks causing data races between nonisolated and nonisolated(nonsending) task-isolated uses}} + // expected-enabled-note @-2 {{sending task-isolated 'x' to @concurrent instance method 'concurrentCaller()' risks causing data races between @concurrent and task-isolated uses}} + + await unspecifiedAsyncUse(x) // expected-disabled-error {{sending 'x' risks causing data races}} + // expected-disabled-note @-1 {{sending nonisolated(nonsending) task-isolated 'x' to nonisolated global function 'unspecifiedAsyncUse' risks causing data races between nonisolated and nonisolated(nonsending) task-isolated uses}} + await nonisolatedAsyncUse(x) // expected-disabled-error {{sending 'x' risks causing data races}} + // expected-disabled-note @-1 {{sending nonisolated(nonsending) task-isolated 'x' to nonisolated global function 'nonisolatedAsyncUse' risks causing data races between nonisolated and nonisolated(nonsending) task-isolated uses}} + await nonisolatedNonSendingAsyncUse(x) + await concurrentAsyncUse(x) // expected-error {{sending 'x' risks causing data races}} + // expected-disabled-note @-1 {{sending nonisolated(nonsending) task-isolated 'x' to nonisolated global function 'concurrentAsyncUse' risks causing data races between nonisolated and nonisolated(nonsending) task-isolated uses}} + // expected-enabled-note @-2 {{sending task-isolated 'x' to @concurrent global function 'concurrentAsyncUse' risks causing data races between @concurrent and task-isolated uses}} +} + +@concurrent func concurrentCallingVariousNonisolated(_ x: NonSendableKlass) async { + await x.unspecifiedCaller() + await x.nonisolatedCaller() + await x.nonisolatedNonSendingCaller() + await x.concurrentCaller() + + await unspecifiedAsyncUse(x) + await nonisolatedAsyncUse(x) + await nonisolatedNonSendingAsyncUse(x) + await concurrentAsyncUse(x) +} diff --git a/test/Concurrency/sendable_checking.swift b/test/Concurrency/sendable_checking.swift index 3ffdc6b7a206a..9b9a96103cc43 100644 --- a/test/Concurrency/sendable_checking.swift +++ b/test/Concurrency/sendable_checking.swift @@ -1,9 +1,11 @@ -// RUN: %target-swift-frontend -target %target-swift-5.0-abi-triple -verify -strict-concurrency=targeted -verify-additional-prefix targeted- -emit-sil -o /dev/null %s -// RUN: %target-swift-frontend -target %target-swift-5.0-abi-triple -verify -strict-concurrency=complete -verify-additional-prefix tns- -verify-additional-prefix complete-and-tns- -emit-sil -o /dev/null %s +// RUN: %target-swift-frontend -target %target-swift-5.0-abi-triple -verify -verify-additional-prefix targeted-and-ni- -strict-concurrency=targeted -verify-additional-prefix targeted- -emit-sil -o /dev/null %s +// RUN: %target-swift-frontend -target %target-swift-5.0-abi-triple -verify -strict-concurrency=complete -verify-additional-prefix tns-ni- -verify-additional-prefix tns- -emit-sil -o /dev/null %s -swift-version 5 -verify-additional-prefix targeted-and-ni- +// RUN: %target-swift-frontend -target %target-swift-5.0-abi-triple -verify -strict-concurrency=complete -verify-additional-prefix tns-ni-ns- -verify-additional-prefix tns- -emit-sil -o /dev/null %s -enable-upcoming-feature NonisolatedNonsendingByDefault -swift-version 5 -DNONISOLATEDNONSENDING // REQUIRES: concurrency // REQUIRES: asserts // REQUIRES: OS=macosx +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault @available(SwiftStdlib 5.1, *) struct NS1 { } @@ -15,7 +17,7 @@ extension NS1: Sendable { } @available(SwiftStdlib 5.1, *) struct NS2 { // expected-note {{consider making struct 'NS2' conform to the 'Sendable' protocol}} - // expected-complete-and-tns-note @-1 {{consider making struct 'NS2' conform to the 'Sendable' protocol}} + // expected-tns-note @-1 {{consider making struct 'NS2' conform to the 'Sendable' protocol}} var ns1: NS1 } @@ -27,7 +29,7 @@ extension NS3: Sendable { } @available(SwiftStdlib 5.1, *) class NS4 { } // expected-note {{class 'NS4' does not conform to the 'Sendable' protocol}} -// expected-complete-and-tns-note @-1 {{class 'NS4' does not conform to the 'Sendable' protocol}} +// expected-tns-note @-1 {{class 'NS4' does not conform to the 'Sendable' protocol}} @available(SwiftStdlib 5.1, *) func acceptCV(_: T) { } @@ -44,15 +46,15 @@ func testCV( acceptCV(ns1array) // expected-warning {{conformance of 'NS1' to 'Sendable' is unavailable}} - acceptCV(ns2) // expected-complete-and-tns-warning {{type 'NS2' does not conform to the 'Sendable' protocol}} + acceptCV(ns2) // expected-tns-warning {{type 'NS2' does not conform to the 'Sendable' protocol}} acceptCV(ns3) // expected-warning {{conformance of 'NS3' to 'Sendable' is only available in macOS 11.0 or newer}} // expected-note @-1 {{add 'if #available' version check}} - acceptCV(ns4) // expected-complete-and-tns-warning {{type 'NS4' does not conform to the 'Sendable' protocol}} + acceptCV(ns4) // expected-tns-warning {{type 'NS4' does not conform to the 'Sendable' protocol}} - acceptCV(fn) // expected-complete-and-tns-warning {{type '() -> Void' does not conform to the 'Sendable' protocol}} - // expected-complete-and-tns-note @-1 {{a function type must be marked '@Sendable' to conform to 'Sendable'}} + acceptCV(fn) // expected-tns-warning {{type '() -> Void' does not conform to the 'Sendable' protocol}} + // expected-tns-note @-1 {{a function type must be marked '@Sendable' to conform to 'Sendable'}} acceptSendableFn(fn) // expected-warning{{passing non-Sendable parameter 'fn' to function expecting a '@Sendable' closure}} } @@ -93,8 +95,8 @@ public actor MyActor: MyProto { func g(ns1: NS1) async { await nonisolatedAsyncFunc1(ns1) - // expected-tns-warning @-1 {{sending 'ns1' risks causing data races}} - // expected-tns-note @-2 {{sending 'self'-isolated 'ns1' to nonisolated global function 'nonisolatedAsyncFunc1' risks causing data races between nonisolated and 'self'-isolated uses}} + // expected-tns-ni-warning @-1 {{sending 'ns1' risks causing data races}} + // expected-tns-ni-note @-2 {{sending 'self'-isolated 'ns1' to nonisolated global function 'nonisolatedAsyncFunc1' risks causing data races between nonisolated and 'self'-isolated uses}} _ = await nonisolatedAsyncFunc2() } } @@ -162,18 +164,18 @@ class Super { @MainActor func bar (x : () -> ()) async {} - // expected-note@-1 {{a function type must be marked '@Sendable' to conform to 'Sendable'}} + // expected-targeted-and-ni-note @-1 {{a function type must be marked '@Sendable' to conform to 'Sendable'}} @MainActor func foo2(x: T) async {} @MainActor func bar2(x: T) async {} - // expected-note@-1 {{consider making generic parameter 'T' conform to the 'Sendable' protocol}} {{14-14=: Sendable}} + // expected-targeted-and-ni-note @-1 {{consider making generic parameter 'T' conform to the 'Sendable' protocol}} {{14-14=: Sendable}} @MainActor func bar3(x: T) async {} - // expected-note@-1 {{consider making generic parameter 'T' conform to the 'Sendable' protocol}} {{25-25= & Sendable}} + // expected-targeted-and-ni-note @-1 {{consider making generic parameter 'T' conform to the 'Sendable' protocol}} {{25-25= & Sendable}} } // Make sure isolation crossing overrides check sendability @@ -182,16 +184,25 @@ class Super { class Sub : Super { override nonisolated func foo(x : () -> ()) async {} + // We do not emit an error for the override with + // NonisolatedNonsendingByDefault since the vtable thunk passes in MainActor + // so we are still in the main actor even though we are nonisolated. In the + // case of that being disabled, we cannot do this since we will hop off the + // actor. override nonisolated func bar(x : () -> ()) async {} - // expected-warning@-1 {{non-Sendable parameter type '() -> ()' cannot be sent from caller of superclass instance method 'bar(x:)' into nonisolated override}} + // expected-targeted-and-ni-warning@-1 {{non-Sendable parameter type '() -> ()' cannot be sent from caller of superclass instance method 'bar(x:)' into nonisolated override}} override nonisolated func foo2(x: T) async {} + // See comment above about why nonisolated overrides of superclass are allowed + // when is enabled NonisolatedNonsendingByDefault. override nonisolated func bar2(x: T) async {} - // expected-warning@-1 {{non-Sendable parameter type 'T' cannot be sent from caller of superclass instance method 'bar2(x:)' into nonisolated override}} + // expected-targeted-and-ni-warning @-1 {{non-Sendable parameter type 'T' cannot be sent from caller of superclass instance method 'bar2(x:)' into nonisolated override}} + // See comment above about why nonisolated overrides of superclass are allowed + // when is enabled NonisolatedNonsendingByDefault. override nonisolated func bar3(x: T) async {} - // expected-warning@-1 {{non-Sendable parameter type 'T' cannot be sent from caller of superclass instance method 'bar3(x:)' into nonisolated override}} + // expected-targeted-and-ni-warning @-1 {{non-Sendable parameter type 'T' cannot be sent from caller of superclass instance method 'bar3(x:)' into nonisolated override}} } @available(SwiftStdlib 5.1, *) @@ -217,7 +228,8 @@ class SubWSafeSubscript : SuperWSafeSubscript { class SuperWUnsafeSubscript { @MainActor subscript(x : T) -> Int { - // expected-note@-1 2{{consider making generic parameter 'T' conform to the 'Sendable' protocol}} + // expected-targeted-and-ni-note @-1 {{consider making generic parameter 'T' conform to the 'Sendable' protocol}} + // expected-targeted-and-ni-note @-2 {{consider making generic parameter 'T' conform to the 'Sendable' protocol}} get async { return 0 } @@ -226,10 +238,15 @@ class SuperWUnsafeSubscript { @available(SwiftStdlib 5.1, *) class SubWUnsafeSubscript : SuperWUnsafeSubscript { + // We do not emit an error for the override with + // NonisolatedNonsendingByDefault since the vtable thunk passes in MainActor + // so we are still in the main actor even though we are nonisolated. In the + // case of that being disabled, we cannot do this since we will hop off the + // actor. override nonisolated subscript(x : T) -> Int { get async { - // expected-warning@-2{{non-Sendable parameter type 'T' cannot be sent from caller of superclass subscript 'subscript(_:)' into nonisolated override}} - // expected-warning@-2{{non-Sendable parameter type 'T' cannot be sent from caller of superclass getter for subscript 'subscript(_:)' into nonisolated override}} + // expected-targeted-and-ni-warning@-2{{non-Sendable parameter type 'T' cannot be sent from caller of superclass subscript 'subscript(_:)' into nonisolated override}} + // expected-targeted-and-ni-warning@-2{{non-Sendable parameter type 'T' cannot be sent from caller of superclass getter for subscript 'subscript(_:)' into nonisolated override}} // there really shouldn't be two warnings produced here, see rdar://110846040 (Sendable diagnostics reported twice for subscript getters) return 0 } @@ -263,7 +280,7 @@ struct CustomActor { final class NonSendable { // expected-note @-1 5 {{class 'NonSendable' does not conform to the 'Sendable' protocol}} // TransferNonSendable emits 3 fewer errors here. - // expected-complete-and-tns-note @-3 {{class 'NonSendable' does not conform to the 'Sendable' protocol}} + // expected-tns-note @-3 {{class 'NonSendable' does not conform to the 'Sendable' protocol}} var value = "" @MainActor @@ -341,6 +358,7 @@ func testNonSendableBaseArg3() async { @Sendable func globalSendable(_ ns: NonSendable) async {} +#if !NONISOLATEDNONSENDING @available(SwiftStdlib 5.1, *) @MainActor func callNonisolatedAsyncClosure( @@ -348,14 +366,15 @@ func callNonisolatedAsyncClosure( g: (NonSendable) async -> Void ) async { await g(ns) - // expected-tns-warning @-1 {{sending 'ns' risks causing data races}} - // expected-tns-note @-2 {{sending main actor-isolated 'ns' to nonisolated callee risks causing data races between nonisolated and main actor-isolated uses}} + // expected-tns-ni-warning @-1 {{sending 'ns' risks causing data races}} + // expected-tns-ni-note @-2 {{sending main actor-isolated 'ns' to nonisolated callee risks causing data races between nonisolated and main actor-isolated uses}} let f: (NonSendable) async -> () = globalSendable // okay await f(ns) - // expected-tns-warning @-1 {{sending 'ns' risks causing data races}} - // expected-tns-note @-2 {{sending main actor-isolated 'ns' to nonisolated callee risks causing data races between nonisolated and main actor-isolated uses}} + // expected-tns-ni-warning @-1 {{sending 'ns' risks causing data races}} + // expected-tns-ni-note @-2 {{sending main actor-isolated 'ns' to nonisolated callee risks causing data races between nonisolated and main actor-isolated uses}} } +#endif @available(SwiftStdlib 5.1, *) func testLocalCaptures() { @@ -364,7 +383,7 @@ func testLocalCaptures() { @Sendable func a2() -> NonSendable { return ns - // expected-complete-and-tns-warning @-1 {{capture of 'ns' with non-Sendable type 'NonSendable' in a '@Sendable' local function}} + // expected-tns-warning @-1 {{capture of 'ns' with non-Sendable type 'NonSendable' in a '@Sendable' local function}} } } diff --git a/test/Concurrency/transfernonsendable.swift b/test/Concurrency/transfernonsendable.swift index ae26109da4a91..755a37371d8f1 100644 --- a/test/Concurrency/transfernonsendable.swift +++ b/test/Concurrency/transfernonsendable.swift @@ -1,4 +1,5 @@ -// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -disable-availability-checking -verify -verify-additional-prefix tns- %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability +// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -disable-availability-checking -verify -verify-additional-prefix tns-ni- -verify-additional-prefix tns- %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability +// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -disable-availability-checking -verify -verify-additional-prefix tns-ni-ns- -verify-additional-prefix tns- %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability -enable-upcoming-feature NonisolatedNonsendingByDefault // This run validates that for specific test cases around closures, we properly // emit errors in the type checker before we run sns. This ensures that we know that @@ -8,6 +9,7 @@ // REQUIRES: concurrency // REQUIRES: swift_feature_GlobalActorIsolatedTypesUsability +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault //////////////////////// // MARK: Declarations // @@ -69,6 +71,7 @@ final class FinalMainActorIsolatedKlass { func useInOut(_ x: inout T) {} func useValue(_ x: T) {} func useValueAsync(_ x: T) async {} +@concurrent func useValueAsyncConcurrent(_ x: T) async {} @MainActor func transferToMain(_ t: T) async {} @@ -106,15 +109,15 @@ enum MyEnum { extension MyActor { func warningIfCallingGetter() async { await self.klass.asyncCall() // expected-complete-warning {{passing argument of non-Sendable type 'NonSendableKlass' outside of actor-isolated context may introduce data races}} - // expected-tns-warning @-1 {{sending 'self.klass' risks causing data races}} - // expected-tns-note @-2 {{sending 'self'-isolated 'self.klass' to nonisolated instance method 'asyncCall()' risks causing data races between nonisolated and 'self'-isolated uses}} + // expected-tns-ni-warning @-1 {{sending 'self.klass' risks causing data races}} + // expected-tns-ni-note @-2 {{sending 'self'-isolated 'self.klass' to nonisolated instance method 'asyncCall()' risks causing data races between nonisolated and 'self'-isolated uses}} } func warningIfCallingAsyncOnFinalField() async { // Since we are calling finalKlass directly, we emit a warning here. await self.finalKlass.asyncCall() // expected-complete-warning {{passing argument of non-Sendable type 'NonSendableKlass' outside of actor-isolated context may introduce data races}} - // expected-tns-warning @-1 {{sending 'self.finalKlass' risks causing data races}} - // expected-tns-note @-2 {{sending 'self'-isolated 'self.finalKlass' to nonisolated instance method 'asyncCall()' risks causing data races between nonisolated and 'self'-isolated uses}} + // expected-tns-ni-warning @-1 {{sending 'self.finalKlass' risks causing data races}} + // expected-tns-ni-note @-2 {{sending 'self'-isolated 'self.finalKlass' to nonisolated instance method 'asyncCall()' risks causing data races between nonisolated and 'self'-isolated uses}} } // We do not warn on this since we warn in the caller of our getter instead. @@ -127,8 +130,8 @@ extension FinalActor { func warningIfCallingAsyncOnFinalField() async { // Since our whole class is final, we emit the error directly here. await self.klass.asyncCall() // expected-complete-warning {{passing argument of non-Sendable type 'NonSendableKlass' outside of actor-isolated context may introduce data races}} - // expected-tns-warning @-1 {{sending 'self.klass' risks causing data races}} - // expected-tns-note @-2 {{sending 'self'-isolated 'self.klass' to nonisolated instance method 'asyncCall()' risks causing data races between nonisolated and 'self'-isolated uses}} + // expected-tns-ni-warning @-1 {{sending 'self.klass' risks causing data races}} + // expected-tns-ni-note @-2 {{sending 'self'-isolated 'self.klass' to nonisolated instance method 'asyncCall()' risks causing data races between nonisolated and 'self'-isolated uses}} } } @@ -1572,8 +1575,12 @@ func functionArgumentIntoClosure(_ x: @escaping () -> ()) async { let a = MainActorIsolatedKlass() var c = NonSendableKlass() for _ in 0..<1024 { - await useValueAsync(c) // expected-tns-warning {{sending 'c' risks causing data races}} - // expected-tns-note @-1 {{sending main actor-isolated 'c' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} + // This works with nonisolated(nonsending) since the first time through the + // loop we are disconnected... meaning that we are ok. The second time + // through the loop, we are now main actor isolated, but again b/c we + // inherit isolation, we are ok. + await useValueAsync(c) // expected-tns-ni-warning {{sending 'c' risks causing data races}} + // expected-tns-ni-note @-1 {{sending main actor-isolated 'c' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} // expected-complete-warning @-2 {{passing argument of non-Sendable type 'NonSendableKlass' outside of main actor-isolated context may introduce data races}} c = a.klass } @@ -1583,8 +1590,8 @@ func functionArgumentIntoClosure(_ x: @escaping () -> ()) async { let a = MainActorIsolatedKlass() var c = NonSendableKlass() for _ in 0..<1024 { - await useValueAsync(c) // expected-tns-warning {{sending 'c' risks causing data races}} - // expected-tns-note @-1 {{sending main actor-isolated 'c' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} + await useValueAsync(c) // expected-tns-ni-warning {{sending 'c' risks causing data races}} + // expected-tns-ni-note @-1 {{sending main actor-isolated 'c' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} // expected-complete-warning @-2 {{passing argument of non-Sendable type 'NonSendableKlass' outside of main actor-isolated context may introduce data races}} c = a.klassLet } @@ -1832,8 +1839,8 @@ actor FunctionWithSendableResultAndIsolationActor { @MainActor func previouslyBrokenTestCase(ns: NonSendableKlass) async -> SendableGenericStruct? { return await { () -> SendableGenericStruct? in - return await ns.getSendableGenericStructAsync() // expected-tns-warning {{sending 'ns' risks causing data races}} - // expected-tns-note @-1 {{sending main actor-isolated 'ns' to nonisolated instance method 'getSendableGenericStructAsync()' risks causing data races between nonisolated and main actor-isolated uses}} + return await ns.getSendableGenericStructAsync() // expected-tns-ni-warning {{sending 'ns' risks causing data races}} + // expected-tns-ni-note @-1 {{sending main actor-isolated 'ns' to nonisolated instance method 'getSendableGenericStructAsync()' risks causing data races between nonisolated and main actor-isolated uses}} }() } @@ -2068,3 +2075,10 @@ func inferLocationOfCapturedTaskIsolatedSelfCorrectly() { } } +nonisolated(nonsending) func testCallNonisolatedNonsending(_ x: NonSendableKlass) async { + await useValueAsync(x) // expected-tns-ni-warning {{sending 'x' risks causing data races}} + // expected-tns-ni-note @-1 {{sending nonisolated(nonsending) task-isolated 'x' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and nonisolated(nonsending) task-isolated uses}} + await useValueAsyncConcurrent(x) // expected-tns-warning {{sending 'x' risks causing data races}} + // expected-tns-ni-note @-1 {{sending nonisolated(nonsending) task-isolated 'x' to nonisolated global function 'useValueAsyncConcurrent' risks causing data races between nonisolated and nonisolated(nonsending) task-isolated uses}} + // expected-tns-ni-ns-note @-2 {{sending task-isolated 'x' to @concurrent global function 'useValueAsyncConcurrent' risks causing data races between @concurrent and task-isolated uses}} +} diff --git a/test/Concurrency/transfernonsendable_asynclet.swift b/test/Concurrency/transfernonsendable_asynclet.swift index 1408f828d39b9..f00bb44a5876b 100644 --- a/test/Concurrency/transfernonsendable_asynclet.swift +++ b/test/Concurrency/transfernonsendable_asynclet.swift @@ -1,7 +1,9 @@ -// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple -verify %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability +// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple -verify %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability -verify-additional-prefix ni- +// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple -verify %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability -enable-upcoming-feature NonisolatedNonsendingByDefault -verify-additional-prefix ni-ns- // REQUIRES: concurrency // REQUIRES: swift_feature_GlobalActorIsolatedTypesUsability +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault //////////////////////// // MARK: Declarations // @@ -84,7 +86,8 @@ struct TwoFieldKlassBox { func asyncLet_Let_ActorIsolated_Simple1() async { let x = NonSendableKlass() async let y = transferToMainInt(x) // expected-warning {{sending 'x' risks causing data races}} - // expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} useValue(x) // expected-note {{access can happen concurrently}} let _ = await y } @@ -92,7 +95,8 @@ func asyncLet_Let_ActorIsolated_Simple1() async { func asyncLet_Let_ActorIsolated_Simple2() async { let x = NonSendableKlass() async let y = transferToMainInt(x) // expected-warning {{sending 'x' risks causing data races}} - // expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} let _ = await y @@ -102,7 +106,8 @@ func asyncLet_Let_ActorIsolated_Simple2() async { func asyncLet_Let_ActorIsolated_Simple3() async { let x = NonSendableKlass() async let y = transferToMainInt(x) // expected-warning {{sending 'x' risks causing data races}} - // expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} // TODO: We shouldn't emit the 2nd error here given the current implementation // since it is only accessible along the else path but we already hit @@ -120,7 +125,8 @@ func asyncLet_Let_ActorIsolated_Simple3() async { func asyncLet_Let_ActorIsolated_Simple4() async { let x = NonSendableKlass() async let y = transferToMainInt(x) // expected-warning {{sending 'x' risks causing data races}} - // expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} if await booleanFlag { useValue(x) // expected-note {{access can happen concurrently}} @@ -133,7 +139,8 @@ func asyncLet_Let_ActorIsolated_Simple4() async { func asyncLet_Let_ActorIsolated_Simple5() async { let x = NonSendableKlass() async let y = transferToMainInt(x) // expected-warning {{sending 'x' risks causing data races}} - // expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} if await booleanFlag { let _ = await y @@ -148,7 +155,8 @@ func asyncLet_Let_ActorIsolated_Simple5() async { func asyncLet_Let_ActorIsolated_AccessFieldsClass1() async { let x = NonSendableKlass() async let y = transferToMainInt(x.field) // expected-warning {{sending 'x' risks causing data races}} - // expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} useValue(x) // expected-note {{access can happen concurrently}} let _ = await y @@ -157,7 +165,8 @@ func asyncLet_Let_ActorIsolated_AccessFieldsClass1() async { func asyncLet_Let_ActorIsolated_AccessFieldsClass2() async { let x = NonSendableKlass() async let y = transferToMainInt(x.field) // expected-warning {{sending 'x' risks causing data races}} - // expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} useValue(x.field) // expected-note {{access can happen concurrently}} let _ = await y @@ -166,7 +175,8 @@ func asyncLet_Let_ActorIsolated_AccessFieldsClass2() async { func asyncLet_Let_ActorIsolated_AccessFieldsClass3() async { let x = NonSendableKlass() async let y = transferToMainInt(x.field) // expected-warning {{sending 'x' risks causing data races}} - // expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} useValue(x.field2) // expected-note {{access can happen concurrently}} let _ = await y @@ -177,7 +187,8 @@ func asyncLet_Let_ActorIsolated_AccessFieldsClass3() async { func asyncLet_Let_ActorIsolated_AccessFieldsStruct1() async { let x = TwoFieldKlassBox() async let y = transferToMainInt(x.k1) // expected-warning {{sending 'x' risks causing data races}} - // expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} useValue(x) // expected-note {{access can happen concurrently}} let _ = await y @@ -186,7 +197,8 @@ func asyncLet_Let_ActorIsolated_AccessFieldsStruct1() async { func asyncLet_Let_ActorIsolated_AccessFieldsStruct2() async { let x = TwoFieldKlassBox() async let y = transferToMainInt(x.k1) // expected-warning {{sending 'x' risks causing data races}} - // expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} useValue(x.k1) // expected-note {{access can happen concurrently}} let _ = await y @@ -195,7 +207,8 @@ func asyncLet_Let_ActorIsolated_AccessFieldsStruct2() async { func asyncLet_Let_ActorIsolated_AccessFieldsStruct3() async { let x = TwoFieldKlassBox() async let y = transferToMainInt(x.k1) // expected-warning {{sending 'x' risks causing data races}} - // expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} useValue(x.k2) // expected-note {{access can happen concurrently}} let _ = await y @@ -204,7 +217,8 @@ func asyncLet_Let_ActorIsolated_AccessFieldsStruct3() async { func asyncLet_Let_ActorIsolated_AccessFieldsStruct4() async { let x = TwoFieldKlassBox() async let y = transferToMainInt(x.k2.field2) // expected-warning {{sending 'x' risks causing data races}} - // expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} useValue(x.k1.field) // expected-note {{access can happen concurrently}} let _ = await y @@ -215,7 +229,8 @@ func asyncLet_Let_ActorIsolated_AccessFieldsStruct4() async { func asyncLet_Let_ActorIsolated_AccessFieldsTuple1() async { let x = (TwoFieldKlassBox(), TwoFieldKlassBox()) async let y = transferToMainInt(x.0.k1) // expected-warning {{sending 'x' risks causing data races}} - // expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} useValue(x) // expected-note {{access can happen concurrently}} let _ = await y @@ -224,7 +239,8 @@ func asyncLet_Let_ActorIsolated_AccessFieldsTuple1() async { func asyncLet_Let_ActorIsolated_AccessFieldsTuple2() async { let x = (TwoFieldKlassBox(), TwoFieldKlassBox()) async let y = transferToMainInt(x.0.k1) // expected-warning {{sending 'x' risks causing data races}} - // expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} useValue(x.1) // expected-note {{access can happen concurrently}} let _ = await y @@ -233,7 +249,8 @@ func asyncLet_Let_ActorIsolated_AccessFieldsTuple2() async { func asyncLet_Let_ActorIsolated_AccessFieldsTuple3() async { let x = (TwoFieldKlassBox(), TwoFieldKlassBox()) async let y = transferToMainInt(x.0.k1) // expected-warning {{sending 'x' risks causing data races}} - // expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} useValue(x.1.k2) // expected-note {{access can happen concurrently}} let _ = await y @@ -242,7 +259,8 @@ func asyncLet_Let_ActorIsolated_AccessFieldsTuple3() async { func asyncLet_Let_ActorIsolated_AccessFieldsTuple4() async { let x = (TwoFieldKlassBox(), TwoFieldKlassBox()) async let y = transferToMainInt(x.1.k1.field2) // expected-warning {{sending 'x' risks causing data races}} - // expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} useValue(x.0.k2.field) // expected-note {{access can happen concurrently}} let _ = await y @@ -253,9 +271,11 @@ func asyncLet_Let_ActorIsolated_CallBuriedInOtherExpr1() async { let x2 = NonSendableKlass() async let y = useValue(transferToMainInt(x) + transferToMainInt(x2)) // expected-warning {{sending 'x' risks causing data races}} - // expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} - // expected-warning @-2 {{sending 'x2' risks causing data races}} - // expected-note @-3 {{sending 'x2' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} + // expected-warning @-3 {{sending 'x2' risks causing data races}} + // expected-ni-note @-4 {{sending 'x2' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-5 {{sending 'x2' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} useValue(x) // expected-note {{access can happen concurrently}} let _ = await y @@ -267,9 +287,11 @@ func asyncLet_Let_ActorIsolated_CallBuriedInOtherExpr2() async { let x2 = NonSendableKlass() async let y = useValue(transferToMainInt(x) + transferToMainInt(x2)) // expected-warning {{sending 'x' risks causing data races}} - // expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} - // expected-warning @-2 {{sending 'x2' risks causing data races}} - // expected-note @-3 {{sending 'x2' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} + // expected-warning @-3 {{sending 'x2' risks causing data races}} + // expected-ni-note @-4 {{sending 'x2' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-5 {{sending 'x2' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} useValue(x2) // expected-note {{access can happen concurrently}} let _ = await y @@ -282,9 +304,11 @@ func asyncLet_Let_ActorIsolated_CallBuriedInOtherExpr3() async { let x2 = NonSendableKlass() async let y = useValue(transferToMainInt(x) + transferToMainInt(x2)) // expected-warning {{sending 'x' risks causing data races}} - // expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} - // expected-warning @-2 {{sending 'x2' risks causing data races}} - // expected-note @-3 {{sending 'x2' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} + // expected-warning @-3 {{sending 'x2' risks causing data races}} + // expected-ni-note @-4 {{sending 'x2' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-5 {{sending 'x2' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} // We only error on the first value captured if multiple values are captured // since we track a single partial_apply as a transfer instruction. @@ -298,8 +322,9 @@ func asyncLet_Let_ActorIsolated_CallBuriedInOtherExpr4() async { async let y = useValue(transferToMainInt(x) + transferToMainInt(x)) // expected-warning @-1:26 {{sending 'x' risks causing data races}} - // expected-note @-2:26 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} - // expected-note @-3:49 {{access can happen concurrently}} + // expected-ni-note @-2:26 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-3:26 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} + // expected-note @-4:49 {{access can happen concurrently}} let _ = await y } @@ -311,8 +336,9 @@ func asyncLet_Let_ActorIsolated_CallBuriedInOtherExpr5() async { async let y = useValue(transferToMainInt(x) + transferToCustomInt(x)) // expected-warning @-1 {{sending 'x' risks causing data races}} - // expected-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} - // expected-note @-3:49 {{access can happen concurrently}} + // expected-ni-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-3 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} + // expected-note @-4:49 {{access can happen concurrently}} let _ = await y } @@ -323,8 +349,9 @@ func asyncLet_Let_ActorIsolated_MultipleAsyncLet1() async { let x = NonSendableKlass() async let y = useValue(transferToMainInt(x)), z = useValue(transferToMainInt(x)) // expected-warning {{sending 'x' risks causing data races}} - // expected-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} - // expected-note @-2:53 {{access can happen concurrently}} + // expected-ni-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} + // expected-note @-3:53 {{access can happen concurrently}} let _ = await y let _ = await z @@ -347,7 +374,8 @@ func asyncLet_Let_ActorIsolated_MultipleAsyncLet3() async { async let y = useValue(transferToMainInt(x)), z = useValue(transferToMainInt(x2)) // expected-warning @-1 {{sending 'x2' risks causing data races}} - // expected-note @-2 {{sending 'x2' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-note @-2 {{sending 'x2' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-3 {{sending 'x2' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} useValue(x2) // expected-note {{access can happen concurrently}} let _ = await y @@ -360,9 +388,11 @@ func asyncLet_Let_ActorIsolated_MultipleAsyncLet4() async { async let y = useValue(transferToMainInt(x)), z = useValue(transferToMainInt(x2)) // expected-warning @-1 {{sending 'x' risks causing data races}} - // expected-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} - // expected-warning @-3 {{sending 'x2' risks causing data races}} - // expected-note @-4 {{sending 'x2' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-3 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} + // expected-warning @-4 {{sending 'x2' risks causing data races}} + // expected-ni-note @-5 {{sending 'x2' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-6 {{sending 'x2' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} let _ = await y let _ = await z @@ -376,9 +406,11 @@ func asyncLet_Let_ActorIsolated_MultipleAsyncLet5() async { async let y = useValue(transferToMainInt(x)), z = useValue(transferToMainInt(x2)) // expected-warning @-1 {{sending 'x' risks causing data races}} - // expected-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} - // expected-warning @-3 {{sending 'x2' risks causing data races}} - // expected-note @-4 {{sending 'x2' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-3 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} + // expected-warning @-4 {{sending 'x2' risks causing data races}} + // expected-ni-note @-5 {{sending 'x2' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-6 {{sending 'x2' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} let _ = await y useValue(x) // expected-note {{access can happen concurrently}} @@ -392,9 +424,11 @@ func asyncLet_Let_ActorIsolated_MultipleAsyncLet6() async { async let y = useValue(transferToMainInt(x)), z = useValue(transferToMainInt(x2)) // expected-warning @-1 {{sending 'x' risks causing data races}} - // expected-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} - // expected-warning @-3 {{sending 'x2' risks causing data races}} - // expected-note @-4 {{sending 'x2' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-3 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} + // expected-warning @-4 {{sending 'x2' risks causing data races}} + // expected-ni-note @-5 {{sending 'x2' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-6 {{sending 'x2' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local @concurrent uses}} let _ = await y useValue(x) // expected-note {{access can happen concurrently}} @@ -722,7 +756,8 @@ func asyncLetWithoutCapture() async { // // NOTE: Error below will go away in next commit. async let x: NonSendableKlass = await returnValueFromMain() - // expected-warning @-1 {{non-Sendable 'NonSendableKlass'-typed result can not be returned from main actor-isolated global function 'returnValueFromMain()' to nonisolated context}} + // expected-ni-warning @-1 {{non-Sendable 'NonSendableKlass'-typed result can not be returned from main actor-isolated global function 'returnValueFromMain()' to nonisolated context}} + // expected-ni-ns-warning @-2 {{non-Sendable 'NonSendableKlass'-typed result can not be returned from main actor-isolated global function 'returnValueFromMain()' to @concurrent context}} let y = await x await transferToMain(y) // expected-warning {{sending 'y' risks causing data races}} // expected-note @-1 {{sending 'y' to main actor-isolated global function 'transferToMain' risks causing data races between main actor-isolated and local nonisolated uses}} @@ -734,7 +769,8 @@ func asyncLet_Let_ActorIsolated_Method() async { let a = MyActor() let x = NonSendableKlass() async let y = a.useKlass(x) // expected-warning {{sending 'x' risks causing data races}} - // expected-note @-1 {{sending 'x' to actor-isolated instance method 'useKlass' risks causing data races between actor-isolated and local nonisolated uses}} + // expected-ni-note @-1 {{sending 'x' to actor-isolated instance method 'useKlass' risks causing data races between actor-isolated and local nonisolated uses}} + // expected-ni-ns-note @-2 {{sending 'x' to actor-isolated instance method 'useKlass' risks causing data races between actor-isolated and local @concurrent uses}} useValue(x) // expected-note {{access can happen concurrently}} let _ = await y diff --git a/test/Concurrency/transfernonsendable_closureliterals_isolationinference.swift b/test/Concurrency/transfernonsendable_closureliterals_isolationinference.swift index 0c52bb1d73cbd..fb3669656dfd4 100644 --- a/test/Concurrency/transfernonsendable_closureliterals_isolationinference.swift +++ b/test/Concurrency/transfernonsendable_closureliterals_isolationinference.swift @@ -1,8 +1,11 @@ -// RUN: %target-swift-frontend -emit-sil -parse-as-library -target %target-swift-5.1-abi-triple -swift-version 5 -strict-concurrency=complete %s -o - | %FileCheck %s -// RUN: %target-swift-frontend -emit-sil -parse-as-library -target %target-swift-5.1-abi-triple -swift-version 6 -verify %s -o /dev/null +// RUN: %target-swift-frontend -emit-sil -parse-as-library -target %target-swift-5.1-abi-triple -swift-version 5 -strict-concurrency=complete %s -o - 2>/dev/null | %FileCheck %s +// RUN: %target-swift-frontend -emit-sil -parse-as-library -target %target-swift-5.1-abi-triple -swift-version 6 -verify %s -o /dev/null -verify-additional-prefix ni- +// RUN: %target-swift-frontend -emit-sil -parse-as-library -target %target-swift-5.1-abi-triple -swift-version 5 -strict-concurrency=complete %s -o - -enable-upcoming-feature NonisolatedNonsendingByDefault 2>/dev/null | %FileCheck %s +// RUN: %target-swift-frontend -emit-sil -parse-as-library -target %target-swift-5.1-abi-triple -swift-version 6 -verify %s -o /dev/null -enable-upcoming-feature NonisolatedNonsendingByDefault -verify-additional-prefix ni-ns- // REQUIRES: concurrency // REQUIRES: asserts +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault // This test validates the behavior of transfernonsendable around // closure literals @@ -204,8 +207,8 @@ func test_CallerAsyncNormal_CalleeSyncNonIsolated() async { // CHECK-LABEL: closure #1 in test_CallerAsyncNormal_CalleeSyncNonIsolated() // CHECK-NEXT: Isolation: global_actor. type: CustomActor - await asyncNormalAcceptsClosure { } // expected-error {{sending value of non-Sendable type '() -> ()' risks causing data races}} - // expected-note @-1 {{sending global actor 'CustomActor'-isolated value of non-Sendable type '() -> ()' to nonisolated global function 'asyncNormalAcceptsClosure' risks causing races in between global actor 'CustomActor'-isolated and nonisolated uses}} + await asyncNormalAcceptsClosure { } // expected-ni-error {{sending value of non-Sendable type '() -> ()' risks causing data races}} + // expected-ni-note @-1 {{sending global actor 'CustomActor'-isolated value of non-Sendable type '() -> ()' to nonisolated global function 'asyncNormalAcceptsClosure' risks causing races in between global actor 'CustomActor'-isolated and nonisolated uses}} // CHECK-LABEL: closure #2 in test_CallerAsyncNormal_CalleeSyncNonIsolated() // CHECK-NEXT: Isolation: nonisolated @@ -244,8 +247,8 @@ func test_CallerAsyncNormal_CalleeAsyncNonIsolated() async { // CHECK-LABEL: closure #1 in test_CallerAsyncNormal_CalleeAsyncNonIsolated() // CHECK-NEXT: Isolation: global_actor. type: CustomActor - await asyncNormalAcceptsAsyncClosure { } // expected-error {{sending value of non-Sendable type '() async -> ()' risks causing data races}} - // expected-note @-1 {{sending global actor 'CustomActor'-isolated value of non-Sendable type '() async -> ()' to nonisolated global function 'asyncNormalAcceptsAsyncClosure' risks causing races in between global actor 'CustomActor'-isolated and nonisolated uses}} + await asyncNormalAcceptsAsyncClosure { } // expected-ni-error {{sending value of non-Sendable type '() async -> ()' risks causing data races}} + // expected-ni-note @-1 {{sending global actor 'CustomActor'-isolated value of non-Sendable type '() async -> ()' to nonisolated global function 'asyncNormalAcceptsAsyncClosure' risks causing races in between global actor 'CustomActor'-isolated and nonisolated uses}} // CHECK-LABEL: closure #2 in test_CallerAsyncNormal_CalleeAsyncNonIsolated() // CHECK-NEXT: Isolation: nonisolated @@ -432,8 +435,8 @@ extension MyActor { // CHECK-LABEL: closure #1 in MyActor.test_CallerAsyncNormal_CalleeSyncNonIsolated() // CHECK-NEXT: Isolation: actor_instance. name: 'self' - await asyncNormalAcceptsClosure { print(self) } // expected-error {{sending value of non-Sendable type '() -> ()' risks causing data races}} - // expected-note @-1 {{sending 'self'-isolated value of non-Sendable type '() -> ()' to nonisolated global function 'asyncNormalAcceptsClosure' risks causing races in between 'self'-isolated and nonisolated uses}} + await asyncNormalAcceptsClosure { print(self) } // expected-ni-error {{sending value of non-Sendable type '() -> ()' risks causing data races}} + // expected-ni-note @-1 {{sending 'self'-isolated value of non-Sendable type '() -> ()' to nonisolated global function 'asyncNormalAcceptsClosure' risks causing races in between 'self'-isolated and nonisolated uses}} // CHECK-LABEL: closure #2 in MyActor.test_CallerAsyncNormal_CalleeSyncNonIsolated() // CHECK-NEXT: Isolation: nonisolated @@ -473,8 +476,8 @@ extension MyActor { // CHECK-LABEL: closure #1 in MyActor.test_CallerAsyncNormal_CalleeAsyncNonIsolated() // CHECK-NEXT: Isolation: actor_instance. name: 'self' - await asyncNormalAcceptsAsyncClosure { print(self) } // expected-error {{sending value of non-Sendable type '() async -> ()' risks causing data races}} - // expected-note @-1 {{sending 'self'-isolated value of non-Sendable type '() async -> ()' to nonisolated global function 'asyncNormalAcceptsAsyncClosure' risks causing races in between 'self'-isolated and nonisolated uses}} + await asyncNormalAcceptsAsyncClosure { print(self) } // expected-ni-error {{sending value of non-Sendable type '() async -> ()' risks causing data races}} + // expected-ni-note @-1 {{sending 'self'-isolated value of non-Sendable type '() async -> ()' to nonisolated global function 'asyncNormalAcceptsAsyncClosure' risks causing races in between 'self'-isolated and nonisolated uses}} // CHECK-LABEL: closure #2 in MyActor.test_CallerAsyncNormal_CalleeAsyncNonIsolated() // CHECK-NEXT: Isolation: nonisolated diff --git a/test/Concurrency/transfernonsendable_functionsubtyping.swift b/test/Concurrency/transfernonsendable_functionsubtyping.swift index de7b2fc8bb893..22739fcc20053 100644 --- a/test/Concurrency/transfernonsendable_functionsubtyping.swift +++ b/test/Concurrency/transfernonsendable_functionsubtyping.swift @@ -1,4 +1,5 @@ // RUN: %target-typecheck-verify-swift -swift-version 6 +// RUN: %target-typecheck-verify-swift -swift-version 6 -enable-upcoming-feature NonisolatedNonsendingByDefault // READ THIS! This file only contains tests that validate that the relevant // function subtyping rules for sending work. Please do not put other tests in @@ -6,6 +7,7 @@ // REQUIRES: concurrency // REQUIRES: asserts +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault //////////////////////// // MARK: Declarations // diff --git a/test/Concurrency/transfernonsendable_global_actor.swift b/test/Concurrency/transfernonsendable_global_actor.swift index fa440e65ec268..b991837f2fd01 100644 --- a/test/Concurrency/transfernonsendable_global_actor.swift +++ b/test/Concurrency/transfernonsendable_global_actor.swift @@ -1,7 +1,9 @@ -// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple -verify -verify-additional-prefix tns- %s -o /dev/null -parse-as-library -enable-upcoming-feature GlobalActorIsolatedTypesUsability +// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple -verify -verify-additional-prefix tns-ni- -verify-additional-prefix tns- %s -o /dev/null -parse-as-library -enable-upcoming-feature GlobalActorIsolatedTypesUsability +// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple -verify -verify-additional-prefix tns-ni-ns- -verify-additional-prefix tns- %s -o /dev/null -parse-as-library -enable-upcoming-feature GlobalActorIsolatedTypesUsability -enable-upcoming-feature NonisolatedNonsendingByDefault // REQUIRES: concurrency // REQUIRES: swift_feature_GlobalActorIsolatedTypesUsability +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault //////////////////////// // MARK: Declarations // @@ -150,8 +152,8 @@ private struct StructContainingValue { // expected-complete-note 2{{}} var x = StructContainingValue() x.x = firstList - await transferToNonIsolated(x) // expected-tns-warning {{sending 'x' risks causing data races}} - // expected-tns-note @-1 {{sending global actor 'CustomActor'-isolated 'x' to nonisolated global function 'transferToNonIsolated' risks causing data races between nonisolated and global actor 'CustomActor'-isolated uses}} + await transferToNonIsolated(x) // expected-tns-ni-warning {{sending 'x' risks causing data races}} + // expected-tns-ni-note @-1 {{sending global actor 'CustomActor'-isolated 'x' to nonisolated global function 'transferToNonIsolated' risks causing data races between nonisolated and global actor 'CustomActor'-isolated uses}} // expected-complete-warning @-2 {{passing argument of non-Sendable type 'StructContainingValue' outside of global actor 'CustomActor'-isolated context may introduce data races}} useValue(x) @@ -174,8 +176,8 @@ private struct StructContainingValue { // expected-complete-note 2{{}} x.1 = firstList - await transferToNonIsolated(x) // expected-tns-warning {{sending 'x' risks causing data races}} - // expected-tns-note @-1 {{sending global actor 'CustomActor'-isolated 'x' to nonisolated global function 'transferToNonIsolated' risks causing data races between nonisolated and global actor 'CustomActor'-isolated uses}} + await transferToNonIsolated(x) // expected-tns-ni-warning {{sending 'x' risks causing data races}} + // expected-tns-ni-note @-1 {{sending global actor 'CustomActor'-isolated 'x' to nonisolated global function 'transferToNonIsolated' risks causing data races between nonisolated and global actor 'CustomActor'-isolated uses}} // expected-complete-warning @-2 {{passing argument of non-Sendable type '(NonSendableLinkedList, NonSendableLinkedList)' outside of global actor 'CustomActor'-isolated context may introduce data races}} // expected-complete-warning @-3 {{passing argument of non-Sendable type '(NonSendableLinkedList, NonSendableLinkedList)' outside of global actor 'CustomActor'-isolated context may introduce data races}} @@ -195,8 +197,8 @@ struct Clock { // We used to crash when inferring the type for the diagnostic below. @MainActor func testIndirectParametersHandledCorrectly() async { let c = Clock() - let _: Int = await c.measure { // expected-tns-warning {{sending value of non-Sendable type '() async -> Int' risks causing data races}} - // expected-tns-note @-1 {{sending main actor-isolated value of non-Sendable type '() async -> Int' to nonisolated instance method 'measure' risks causing races in between main actor-isolated and nonisolated uses}} + let _: Int = await c.measure { // expected-tns-ni-warning {{sending value of non-Sendable type '() async -> Int' risks causing data races}} + // expected-tns-ni-note @-1 {{sending main actor-isolated value of non-Sendable type '() async -> Int' to nonisolated instance method 'measure' risks causing races in between main actor-isolated and nonisolated uses}} try! await c.sleep() } } @@ -255,8 +257,8 @@ struct Clock { let erased: () -> Void = closure - await useValueAsync(erased) // expected-tns-warning {{sending 'erased' risks causing data races}} - // expected-tns-note @-1 {{sending main actor-isolated 'erased' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} + await useValueAsync(erased) // expected-tns-ni-warning {{sending 'erased' risks causing data races}} + // expected-tns-ni-note @-1 {{sending main actor-isolated 'erased' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} // expected-complete-warning @-2 {{passing argument of non-Sendable type '() -> Void' outside of main actor-isolated context may introduce data races}} // expected-complete-note @-3 {{a function type must be marked '@Sendable' to conform to 'Sendable'}} } @@ -264,8 +266,8 @@ struct Clock { @MainActor func synchronousActorIsolatedFunctionError() async { let erased: () -> Void = mainActorFunction - await useValueAsync(erased) // expected-tns-warning {{sending 'erased' risks causing data races}} - // expected-tns-note @-1 {{sending main actor-isolated 'erased' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} + await useValueAsync(erased) // expected-tns-ni-warning {{sending 'erased' risks causing data races}} + // expected-tns-ni-note @-1 {{sending main actor-isolated 'erased' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} // expected-complete-warning @-2 {{passing argument of non-Sendable type '() -> Void' outside of main actor-isolated context may introduce data races}} // expected-complete-note @-3 {{a function type must be marked '@Sendable' to conform to 'Sendable'}} } @@ -273,8 +275,8 @@ struct Clock { @MainActor func synchronousActorIsolatedGenericFunctionError(_ t: T) async { let erased: (T) -> Void = useValueMainActor - await useValueAsync(erased) // expected-tns-warning {{sending 'erased' risks causing data races}} - // expected-tns-note @-1 {{sending main actor-isolated 'erased' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} + await useValueAsync(erased) // expected-tns-ni-warning {{sending 'erased' risks causing data races}} + // expected-tns-ni-note @-1 {{sending main actor-isolated 'erased' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} // expected-complete-warning @-2 {{passing argument of non-Sendable type '(T) -> Void' outside of main actor-isolated context may introduce data races}} // expected-complete-note @-3 {{a function type must be marked '@Sendable' to conform to 'Sendable'}} } @@ -287,8 +289,8 @@ struct Clock { let t = Test() let erased: () -> Void = t.foo - await useValueAsync(erased) // expected-tns-warning {{sending 'erased' risks causing data races}} - // expected-tns-note @-1 {{sending main actor-isolated 'erased' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} + await useValueAsync(erased) // expected-tns-ni-warning {{sending 'erased' risks causing data races}} + // expected-tns-ni-note @-1 {{sending main actor-isolated 'erased' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} // expected-complete-warning @-2 {{passing argument of non-Sendable type '() -> Void' outside of main actor-isolated context may introduce data races}} // expected-complete-note @-3 {{a function type must be marked '@Sendable' to conform to 'Sendable'}} } @@ -301,8 +303,8 @@ struct Clock { let t = Test() let erased: () -> Void = t.foo - await useValueAsync(erased) // expected-tns-warning {{sending 'erased' risks causing data races}} - // expected-tns-note @-1 {{sending main actor-isolated 'erased' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} + await useValueAsync(erased) // expected-tns-ni-warning {{sending 'erased' risks causing data races}} + // expected-tns-ni-note @-1 {{sending main actor-isolated 'erased' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} // expected-complete-warning @-2 {{passing argument of non-Sendable type '() -> Void' outside of main actor-isolated context may introduce data races}} // expected-complete-note @-3 {{a function type must be marked '@Sendable' to conform to 'Sendable'}} } diff --git a/test/Concurrency/transfernonsendable_global_actor_nonsendable.swift b/test/Concurrency/transfernonsendable_global_actor_nonsendable.swift index f4fe9669ef6af..b6553a9cc6807 100644 --- a/test/Concurrency/transfernonsendable_global_actor_nonsendable.swift +++ b/test/Concurrency/transfernonsendable_global_actor_nonsendable.swift @@ -1,4 +1,5 @@ // RUN: %target-swift-frontend -emit-sil -swift-version 6 -target %target-swift-5.1-abi-triple -verify %s -o /dev/null -parse-as-library +// RUN: %target-swift-frontend -emit-sil -swift-version 6 -target %target-swift-5.1-abi-triple -verify %s -o /dev/null -parse-as-library -enable-upcoming-feature NonisolatedNonsendingByDefault // READ THIS: This test is testing specifically behavior around global actor // isolated types that are nonsendable. This is a bit of a corner case so we use @@ -6,6 +7,7 @@ // REQUIRES: concurrency // REQUIRES: asserts +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault //////////////////////// // MARK: Declarations // diff --git a/test/Concurrency/transfernonsendable_global_actor_sending.swift b/test/Concurrency/transfernonsendable_global_actor_sending.swift index a0fe45df8881c..37c446a1eee62 100644 --- a/test/Concurrency/transfernonsendable_global_actor_sending.swift +++ b/test/Concurrency/transfernonsendable_global_actor_sending.swift @@ -1,9 +1,13 @@ // RUN: %target-swift-frontend -emit-sil -swift-version 6 -target %target-swift-5.1-abi-triple -verify %s -o /dev/null -parse-as-library +// RUN: %target-swift-frontend -emit-sil -swift-version 6 -target %target-swift-5.1-abi-triple -verify %s -o /dev/null -parse-as-library -enable-upcoming-feature NonisolatedNonsendingByDefault + // README: Once we loosen the parser so that sending is rejected in Sema // instead of the parser, move into the normal // transfernonsendable_global_actor.swift +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault + //////////////////////// // MARK: Declarations // //////////////////////// @@ -30,9 +34,8 @@ func useValue(_ t: T) {} @MainActor func testGlobalFakeInit() { let ns = NonSendableKlass() - // Will be resolved once @MainActor is @Sendable. - Task.fakeInit { @MainActor in // expected-error {{passing closure as a 'sending' parameter risks causing data races between main actor-isolated code and concurrent execution of the closure}} - print(ns) // expected-note {{closure captures 'ns' which is accessible to main actor-isolated code}} + Task.fakeInit { @MainActor in + print(ns) } useValue(ns) diff --git a/test/Concurrency/transfernonsendable_global_actor_swift6.swift b/test/Concurrency/transfernonsendable_global_actor_swift6.swift index a8bf80094f830..9c18e13977c77 100644 --- a/test/Concurrency/transfernonsendable_global_actor_swift6.swift +++ b/test/Concurrency/transfernonsendable_global_actor_swift6.swift @@ -1,4 +1,5 @@ -// RUN: %target-swift-frontend -emit-sil -swift-version 6 -target %target-swift-5.1-abi-triple -verify %s -o /dev/null -parse-as-library +// RUN: %target-swift-frontend -emit-sil -swift-version 6 -target %target-swift-5.1-abi-triple -verify -verify-additional-prefix ni- %s -o /dev/null -parse-as-library +// RUN: %target-swift-frontend -emit-sil -swift-version 6 -target %target-swift-5.1-abi-triple -verify -verify-additional-prefix ni-ns- %s -o /dev/null -parse-as-library -enable-upcoming-feature NonisolatedNonsendingByDefault // README: This is testing specific patterns around global actors that are // slightly different in between swift 5 and swift 6. The normal global actor @@ -6,6 +7,7 @@ // REQUIRES: concurrency // REQUIRES: asserts +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault //////////////////////// // MARK: Declarations // @@ -44,22 +46,22 @@ var booleanFlag: Bool { false } let erased: () -> Void = closure - await useValueAsync(erased) // expected-error {{sending 'erased' risks causing data races}} - // expected-note @-1 {{sending main actor-isolated 'erased' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} + await useValueAsync(erased) // expected-ni-error {{sending 'erased' risks causing data races}} + // expected-ni-note @-1 {{sending main actor-isolated 'erased' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} } @MainActor func synchronousActorIsolatedFunctionError() async { let erased: () -> Void = mainActorFunction - await useValueAsync(erased) // expected-error {{sending 'erased' risks causing data races}} - // expected-note @-1 {{sending main actor-isolated 'erased' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} + await useValueAsync(erased) // expected-ni-error {{sending 'erased' risks causing data races}} + // expected-ni-note @-1 {{sending main actor-isolated 'erased' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} } @MainActor func synchronousActorIsolatedGenericFunctionError(_ t: T) async { let erased: (T) -> Void = useValueMainActor - await useValueAsync(erased) // expected-error {{sending 'erased' risks causing data races}} - // expected-note @-1 {{sending main actor-isolated 'erased' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} + await useValueAsync(erased) // expected-ni-error {{sending 'erased' risks causing data races}} + // expected-ni-note @-1 {{sending main actor-isolated 'erased' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} } @MainActor func synchronousActorIsolatedClassMethodError() async { @@ -70,8 +72,8 @@ var booleanFlag: Bool { false } let t = Test() let erased: () -> Void = t.foo - await useValueAsync(erased) // expected-error {{sending 'erased' risks causing data races}} - // expected-note @-1 {{sending main actor-isolated 'erased' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} + await useValueAsync(erased) // expected-ni-error {{sending 'erased' risks causing data races}} + // expected-ni-note @-1 {{sending main actor-isolated 'erased' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} } @MainActor func synchronousActorIsolatedFinalClassMethodError() async { @@ -82,6 +84,6 @@ var booleanFlag: Bool { false } let t = Test() let erased: () -> Void = t.foo - await useValueAsync(erased) // expected-error {{sending 'erased' risks causing data races}} - // expected-note @-1 {{sending main actor-isolated 'erased' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} + await useValueAsync(erased) // expected-ni-error {{sending 'erased' risks causing data races}} + // expected-ni-note @-1 {{sending main actor-isolated 'erased' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} } diff --git a/test/Concurrency/transfernonsendable_initializers.swift b/test/Concurrency/transfernonsendable_initializers.swift index 4eb41f9ec759d..b298fadbb3835 100644 --- a/test/Concurrency/transfernonsendable_initializers.swift +++ b/test/Concurrency/transfernonsendable_initializers.swift @@ -1,7 +1,9 @@ -// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple -swift-version 6 -verify %s -o /dev/null +// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple -swift-version 6 -verify -verify-additional-prefix ni- %s -o /dev/null +// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple -swift-version 6 -verify -verify-additional-prefix ni-ns- %s -o /dev/null -enable-upcoming-feature NonisolatedNonsendingByDefault // REQUIRES: concurrency // REQUIRES: asserts +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault // This test validates the behavior of transfernonsendable around initializers. @@ -34,7 +36,8 @@ actor ActorWithSynchronousNonIsolatedInit { // TODO: This should say actor isolated. let _ = { @MainActor in print(newK) // expected-error {{sending 'newK' risks causing data races}} - // expected-note @-1 {{task-isolated 'newK' is captured by a main actor-isolated closure. main actor-isolated uses in closure may race against later nonisolated uses}} + // expected-ni-note @-1 {{task-isolated 'newK' is captured by a main actor-isolated closure. main actor-isolated uses in closure may race against later nonisolated uses}} + // expected-ni-ns-note @-2 {{task-isolated 'newK' is captured by a main actor-isolated closure. main actor-isolated uses in closure may race against later nonisolated uses}} } } diff --git a/test/Concurrency/transfernonsendable_isolationcrossing_partialapply.swift b/test/Concurrency/transfernonsendable_isolationcrossing_partialapply.swift index c24a94e778149..0a293980726a1 100644 --- a/test/Concurrency/transfernonsendable_isolationcrossing_partialapply.swift +++ b/test/Concurrency/transfernonsendable_isolationcrossing_partialapply.swift @@ -1,7 +1,9 @@ // RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -disable-availability-checking -verify %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability +// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -disable-availability-checking -verify %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability -enable-upcoming-feature NonisolatedNonsendingByDefault // REQUIRES: concurrency // REQUIRES: swift_feature_GlobalActorIsolatedTypesUsability +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault // This test validates how we handle partial applies that are isolated to a // specific isolation domain (causing isolation crossings to occur). diff --git a/test/Concurrency/transfernonsendable_nonisolated.swift b/test/Concurrency/transfernonsendable_nonisolated.swift index 73aaf5b82225e..6e208f6a2bb54 100644 --- a/test/Concurrency/transfernonsendable_nonisolated.swift +++ b/test/Concurrency/transfernonsendable_nonisolated.swift @@ -1,7 +1,9 @@ // RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple -verify %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability +// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple -verify %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability -enable-upcoming-feature NonisolatedNonsendingByDefault // REQUIRES: concurrency // REQUIRES: swift_feature_GlobalActorIsolatedTypesUsability +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault // This test validates behavior of transfernonsendable around nonisolated // functions and fields. diff --git a/test/Concurrency/transfernonsendable_nonisolatedunsafe.swift b/test/Concurrency/transfernonsendable_nonisolatedunsafe.swift index ab9fb1752b5a1..13f1c2e414442 100644 --- a/test/Concurrency/transfernonsendable_nonisolatedunsafe.swift +++ b/test/Concurrency/transfernonsendable_nonisolatedunsafe.swift @@ -1,10 +1,12 @@ // RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple -verify -verify-additional-prefix tns- %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability +// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple -verify -verify-additional-prefix tns- %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability -enable-upcoming-feature NonisolatedNonsendingByDefault // READ THIS: This test is intended to centralize all tests that use // nonisolated(unsafe). // REQUIRES: concurrency // REQUIRES: swift_feature_GlobalActorIsolatedTypesUsability +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault //////////////////////// // MARK: Declarations // diff --git a/test/Concurrency/transfernonsendable_objc.swift b/test/Concurrency/transfernonsendable_objc.swift index b726878b9c7d0..56099d5097b84 100644 --- a/test/Concurrency/transfernonsendable_objc.swift +++ b/test/Concurrency/transfernonsendable_objc.swift @@ -1,8 +1,9 @@ -// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -enable-upcoming-feature RegionBasedIsolation -target %target-swift-5.1-abi-triple %s -o /dev/null -import-objc-header %S/Inputs/transfernonsendable_objc.h -enable-upcoming-feature GlobalActorIsolatedTypesUsability +// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple %s -o /dev/null -import-objc-header %S/Inputs/transfernonsendable_objc.h -enable-upcoming-feature GlobalActorIsolatedTypesUsability +// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple %s -o /dev/null -import-objc-header %S/Inputs/transfernonsendable_objc.h -enable-upcoming-feature GlobalActorIsolatedTypesUsability -enable-upcoming-feature NonisolatedNonsendingByDefault // REQUIRES: objc_interop // REQUIRES: swift_feature_GlobalActorIsolatedTypesUsability -// REQUIRES: swift_feature_RegionBasedIsolation +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault import Foundation diff --git a/test/Concurrency/transfernonsendable_ownership.swift b/test/Concurrency/transfernonsendable_ownership.swift index fe0fd7102e736..68bed57c74b37 100644 --- a/test/Concurrency/transfernonsendable_ownership.swift +++ b/test/Concurrency/transfernonsendable_ownership.swift @@ -1,4 +1,5 @@ // RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple -verify -enable-upcoming-feature GlobalActorIsolatedTypesUsability %s -o /dev/null +// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple -verify -enable-upcoming-feature GlobalActorIsolatedTypesUsability %s -o /dev/null -enable-upcoming-feature NonisolatedNonsendingByDefault // This test validates the behavior of transfer non sendable around ownership // constructs like non copyable types, consuming/borrowing parameters, and inout @@ -6,6 +7,7 @@ // REQUIRES: concurrency // REQUIRES: swift_feature_GlobalActorIsolatedTypesUsability +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault //////////////////////// // MARK: Declarations // diff --git a/test/Concurrency/transfernonsendable_preconcurrency.swift b/test/Concurrency/transfernonsendable_preconcurrency.swift index 08f87c3fa89cf..7577948bf8c27 100644 --- a/test/Concurrency/transfernonsendable_preconcurrency.swift +++ b/test/Concurrency/transfernonsendable_preconcurrency.swift @@ -11,9 +11,11 @@ // Test swift 6 // RUN: %target-swift-frontend -swift-version 6 %s -emit-sil -o /dev/null -verify -verify-additional-prefix swift-6- -parse-as-library -I %t -target %target-swift-5.1-abi-triple +// RUN: %target-swift-frontend -swift-version 6 %s -emit-sil -o /dev/null -verify -verify-additional-prefix swift-6- -parse-as-library -I %t -target %target-swift-5.1-abi-triple -enable-upcoming-feature NonisolatedNonsendingByDefault // REQUIRES: concurrency // REQUIRES: asserts +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault // README: This test is meant to test the interaction of transfernonsendable and // preconcurrency. Please only keep such tests in this file. diff --git a/test/Concurrency/transfernonsendable_preconcurrency_sending.swift b/test/Concurrency/transfernonsendable_preconcurrency_sending.swift index dd2d68a356723..a46ee44de1dc2 100644 --- a/test/Concurrency/transfernonsendable_preconcurrency_sending.swift +++ b/test/Concurrency/transfernonsendable_preconcurrency_sending.swift @@ -11,9 +11,11 @@ // Test swift 6 // RUN: %target-swift-frontend -swift-version 6 %s -emit-sil -o /dev/null -verify -verify-additional-prefix swift-6- -parse-as-library -I %t -target %target-swift-5.1-abi-triple +// RUN: %target-swift-frontend -swift-version 6 %s -emit-sil -o /dev/null -verify -verify-additional-prefix swift-6- -parse-as-library -I %t -target %target-swift-5.1-abi-triple -enable-upcoming-feature NonisolatedNonsendingByDefault // REQUIRES: concurrency // REQUIRES: asserts +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault // README: This test is meant to test the interaction of transfernonsendable, // preconcurrency, and transferring. Please only keep such tests in this file. diff --git a/test/Concurrency/transfernonsendable_rbi_result.swift b/test/Concurrency/transfernonsendable_rbi_result.swift index ea730c83b2d92..fc86d0ca4519d 100644 --- a/test/Concurrency/transfernonsendable_rbi_result.swift +++ b/test/Concurrency/transfernonsendable_rbi_result.swift @@ -1,7 +1,9 @@ -// RUN: %target-swift-frontend -target %target-swift-5.1-abi-triple -swift-version 6 -parse-as-library %s -emit-sil -o /dev/null -verify +// RUN: %target-swift-frontend -target %target-swift-5.1-abi-triple -swift-version 6 -disable-availability-checking -parse-as-library %s -emit-sil -o /dev/null -verify -verify-additional-prefix ni- +// RUN: %target-swift-frontend -target %target-swift-5.1-abi-triple -swift-version 6 -disable-availability-checking -parse-as-library %s -emit-sil -o /dev/null -verify -verify-additional-prefix ni-ns- -enable-upcoming-feature NonisolatedNonsendingByDefault // REQUIRES: asserts // REQUIRES: concurrency +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault /////////////////////// // MARK: Declaration // @@ -20,9 +22,13 @@ struct CustomActor { class NonSendable {} // expected-note 3{{}} func passNonSendable(_: NonSendable) async { } +func passTwoNonSendable(_: NonSendable, _: NonSendable) async { } func returnsNonSendable() async -> NonSendable { NonSendable() } +@MainActor +func sendToMain(_ t: T) async {} + @MainActor func mainActorPassNonSendable(_: NonSendable) async { } @@ -93,9 +99,22 @@ actor A { func callNonisolatedFuncsFromActor(ns: NonSendable) async { // Non-sendable value passed from nonisolated to actor isolated + // We do not error in ni-ns since we just merge pass non sendable. await passNonSendable(ns) - // expected-error @-1 {{sending 'ns' risks causing data races}} - // expected-note @-2 {{sending 'self'-isolated 'ns' to nonisolated global function 'passNonSendable' risks causing data races between nonisolated and 'self'-isolated uses}} + // expected-ni-error @-1 {{sending 'ns' risks causing data races}} + // expected-ni-note @-2 {{sending 'self'-isolated 'ns' to nonisolated global function 'passNonSendable' risks causing data races between nonisolated and 'self'-isolated uses}} + + // We error here in both modes but in different places. In NI mode, we error + // on passing ns to a nonisolated function. With ni-ns, we do not error + // there since we inherit isolation from the caller. + // + // In contrast, when ni-ns is enabled, we error on sendToMain since we merge + // ns2 into ns's region causing it to be self-isolated. + let ns2 = NonSendable() + await passTwoNonSendable(ns, ns2) // expected-ni-error {{sending 'ns' risks causing data races}} + // expected-ni-note @-1 {{sending 'self'-isolated 'ns' to nonisolated global function 'passTwoNonSendable' risks causing data races between nonisolated and 'self'-isolated uses}} + await sendToMain(ns2) // expected-ni-ns-error {{sending 'ns2' risks causing data races}} + // expected-ni-ns-note @-1 {{sending 'self'-isolated 'ns2' to main actor-isolated global function 'sendToMain' risks causing data races between main actor-isolated and 'self'-isolated uses}} _ = await returnsNonSendable() } diff --git a/test/Concurrency/transfernonsendable_region_based_sendability.swift b/test/Concurrency/transfernonsendable_region_based_sendability.swift index 30932af4c7dbb..1c39c643de782 100644 --- a/test/Concurrency/transfernonsendable_region_based_sendability.swift +++ b/test/Concurrency/transfernonsendable_region_based_sendability.swift @@ -1,7 +1,9 @@ // RUN: %target-swift-frontend -strict-concurrency=complete -target %target-swift-5.1-abi-triple -parse-as-library -emit-sil -o /dev/null -verify -verify-additional-prefix tns- %s -enable-upcoming-feature GlobalActorIsolatedTypesUsability +// RUN: %target-swift-frontend -strict-concurrency=complete -target %target-swift-5.1-abi-triple -parse-as-library -emit-sil -o /dev/null -verify -verify-additional-prefix tns- %s -enable-upcoming-feature GlobalActorIsolatedTypesUsability -enable-upcoming-feature NonisolatedNonsendingByDefault // REQUIRES: concurrency // REQUIRES: swift_feature_GlobalActorIsolatedTypesUsability +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault /* This file tests the early features of the flow-sensitive Sendable checking implemented by the TransferNonSendable SIL pass. diff --git a/test/Concurrency/transfernonsendable_sending_params.swift b/test/Concurrency/transfernonsendable_sending_params.swift index e71857f4f2a87..55a06267503d2 100644 --- a/test/Concurrency/transfernonsendable_sending_params.swift +++ b/test/Concurrency/transfernonsendable_sending_params.swift @@ -1,7 +1,9 @@ -// RUN: %target-swift-frontend -emit-sil -parse-as-library -target %target-swift-5.1-abi-triple -strict-concurrency=complete -verify %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability +// RUN: %target-swift-frontend -emit-sil -parse-as-library -target %target-swift-5.1-abi-triple -strict-concurrency=complete -verify -verify-additional-prefix ni- %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability +// RUN: %target-swift-frontend -emit-sil -parse-as-library -target %target-swift-5.1-abi-triple -strict-concurrency=complete -verify -verify-additional-prefix ni-ns- %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability -enable-upcoming-feature NonisolatedNonsendingByDefault // REQUIRES: concurrency // REQUIRES: swift_feature_GlobalActorIsolatedTypesUsability +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault //////////////////////// // MARK: Declarations // diff --git a/test/Concurrency/transfernonsendable_sending_results.swift b/test/Concurrency/transfernonsendable_sending_results.swift index a3615b29546fe..4ffacba9f1a6e 100644 --- a/test/Concurrency/transfernonsendable_sending_results.swift +++ b/test/Concurrency/transfernonsendable_sending_results.swift @@ -1,7 +1,9 @@ -// RUN: %target-swift-frontend -emit-sil -parse-as-library -strict-concurrency=complete -target %target-swift-5.1-abi-triple -verify %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability +// RUN: %target-swift-frontend -emit-sil -parse-as-library -strict-concurrency=complete -target %target-swift-5.1-abi-triple -verify %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability -verify-additional-prefix ni- +// RUN: %target-swift-frontend -emit-sil -parse-as-library -strict-concurrency=complete -target %target-swift-5.1-abi-triple -verify %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability -enable-upcoming-feature NonisolatedNonsendingByDefault -verify-additional-prefix ni-ns- // REQUIRES: concurrency // REQUIRES: swift_feature_GlobalActorIsolatedTypesUsability +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault //////////////////////// // MARK: Declarations // @@ -141,7 +143,8 @@ func transferInAndOut(_ x: sending NonSendableKlass) -> sending NonSendableKlass func transferReturnArg(_ x: NonSendableKlass) -> sending NonSendableKlass { return x // expected-warning {{sending 'x' risks causing data races}} - // expected-note @-1 {{task-isolated 'x' cannot be a 'sending' result. task-isolated uses may race with caller uses}} + // expected-ni-note @-1 {{task-isolated 'x' cannot be a 'sending' result. task-isolated uses may race with caller uses}} + // expected-ni-ns-note @-2 {{task-isolated 'x' cannot be a 'sending' result. task-isolated uses may race with caller uses}} } // TODO: This will be fixed once I represent @MainActor on func types. @@ -238,7 +241,8 @@ func asyncLetReabstractionThunkTest() async { func asyncLetReabstractionThunkTest2() async { // We emit the error here since we are returning a main actor isolated value. async let newValue: NonSendableKlass = await getMainActorValueAsync() - // expected-warning @-1 {{non-Sendable 'NonSendableKlass'-typed result can not be returned from main actor-isolated global function 'getMainActorValueAsync()' to nonisolated context}} + // expected-ni-warning @-1 {{non-Sendable 'NonSendableKlass'-typed result can not be returned from main actor-isolated global function 'getMainActorValueAsync()' to nonisolated context}} + // expected-ni-ns-warning @-2 {{non-Sendable 'NonSendableKlass'-typed result can not be returned from main actor-isolated global function 'getMainActorValueAsync()' to @concurrent context}} let _ = await newValue @@ -261,7 +265,8 @@ func asyncLetReabstractionThunkTest2() async { @MainActor func asyncLetReabstractionThunkTestGlobalActor2() async { // We emit the error here since we are returning a main actor isolated value. async let newValue: NonSendableKlass = await getMainActorValueAsync() - // expected-warning @-1 {{non-Sendable 'NonSendableKlass'-typed result can not be returned from main actor-isolated global function 'getMainActorValueAsync()' to nonisolated context}} + // expected-ni-warning @-1 {{non-Sendable 'NonSendableKlass'-typed result can not be returned from main actor-isolated global function 'getMainActorValueAsync()' to nonisolated context}} + // expected-ni-ns-warning @-2 {{non-Sendable 'NonSendableKlass'-typed result can not be returned from main actor-isolated global function 'getMainActorValueAsync()' to @concurrent context}} let _ = await newValue diff --git a/test/Concurrency/transfernonsendable_typed_errors.swift b/test/Concurrency/transfernonsendable_typed_errors.swift index cade1abcc2e03..f563ecfdd843a 100644 --- a/test/Concurrency/transfernonsendable_typed_errors.swift +++ b/test/Concurrency/transfernonsendable_typed_errors.swift @@ -1,7 +1,9 @@ // RUN: %target-swift-frontend -swift-version 6 -Xllvm -sil-regionbasedisolation-force-use-of-typed-errors -emit-sil -o /dev/null %s -verify -target %target-swift-5.1-abi-triple +// RUN: %target-swift-frontend -swift-version 6 -Xllvm -sil-regionbasedisolation-force-use-of-typed-errors -emit-sil -o /dev/null %s -verify -target %target-swift-5.1-abi-triple -enable-upcoming-feature NonisolatedNonsendingByDefault // REQUIRES: concurrency // REQUIRES: asserts +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault // READ THIS: This test is only intended to test typed errors that are fallback // error paths that are only invoked if we can't find a name for the value being diff --git a/test/Concurrency/transfernonsendable_unavailable_conformance.swift b/test/Concurrency/transfernonsendable_unavailable_conformance.swift index 883b1447b07fc..aac9d80b2bb87 100644 --- a/test/Concurrency/transfernonsendable_unavailable_conformance.swift +++ b/test/Concurrency/transfernonsendable_unavailable_conformance.swift @@ -1,8 +1,9 @@ -// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -enable-upcoming-feature RegionBasedIsolation -target %target-swift-5.1-abi-triple -verify %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability +// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple -verify %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability +// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple -verify %s -o /dev/null -enable-upcoming-feature GlobalActorIsolatedTypesUsability -enable-upcoming-feature NonisolatedNonsendingByDefault // REQUIRES: concurrency // REQUIRES: swift_feature_GlobalActorIsolatedTypesUsability -// REQUIRES: swift_feature_RegionBasedIsolation +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault // This test makes sure that we treat types with an unavailable Sendable // conformance as being non-Sendable. diff --git a/test/Concurrency/transfernonsendable_warning_until_swift6.swift b/test/Concurrency/transfernonsendable_warning_until_swift6.swift index 9f194ee040248..3548524be7c9e 100644 --- a/test/Concurrency/transfernonsendable_warning_until_swift6.swift +++ b/test/Concurrency/transfernonsendable_warning_until_swift6.swift @@ -1,6 +1,8 @@ // RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple -verify %s -o /dev/null -swift-version 6 +// RUN: %target-swift-frontend -emit-sil -strict-concurrency=complete -target %target-swift-5.1-abi-triple -verify %s -o /dev/null -swift-version 6 -enable-upcoming-feature NonisolatedNonsendingByDefault // REQUIRES: concurrency +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault // This test makes sure that all of our warnings are errors in swift6 mode. diff --git a/test/SILOptimizer/missing_returns.swift b/test/SILOptimizer/missing_returns.swift index e6bb0299c779c..986a46567115c 100644 --- a/test/SILOptimizer/missing_returns.swift +++ b/test/SILOptimizer/missing_returns.swift @@ -10,29 +10,29 @@ struct MissingGetterSubscript1 { subscript (i : Int) -> Int { - } // expected-error {{missing return in getter expected to return 'Int'}} + } // expected-error {{missing return in getter for subscript expected to return 'Int'}} } // MARK: `decl/var/properties` struct X {} -var x13: X {} // expected-error {{missing return in getter expected to return 'X'}} +var x13: X {} // expected-error {{missing return in getter for var expected to return 'X'}} struct X14 {} extension X14 { var x14: X { - } // expected-error {{missing return in getter expected to return 'X'}} + } // expected-error {{missing return in getter for property expected to return 'X'}} } // https://github.com/apple/swift/issues/57936 enum E1_57936 { - var foo: Int {} // expected-error{{missing return in getter expected to return 'Int'}} + var foo: Int {} // expected-error{{missing return in getter for property expected to return 'Int'}} } enum E2_57936 { - var foo: T {} // expected-error{{missing return in getter expected to return 'T'}} + var foo: T {} // expected-error{{missing return in getter for property expected to return 'T'}} } // MARK: `decl/var/result_builders` @@ -51,7 +51,7 @@ var fv_nop: () { } var fv_missing: String { -} // expected-error {{missing return in getter expected to return 'String'}} +} // expected-error {{missing return in getter for var expected to return 'String'}} enum S_nop { subscript() -> () { @@ -60,30 +60,30 @@ enum S_nop { enum S_missing { subscript() -> String { - } // expected-error {{missing return in getter expected to return 'String'}} + } // expected-error {{missing return in getter for subscript expected to return 'String'}} } // MARK: `Sema/generic-subscript` struct S_generic_subscript_missing_return { subscript(x: Int) -> Value { - } // expected-error {{missing return in getter expected to return 'Value'}} + } // expected-error {{missing return in getter for subscript expected to return 'Value'}} } // MARK: New Test Cases enum MyEmptyType {} extension MyEmptyType { - var i: Int {} // expected-error{{missing return in getter expected to return 'Int'}} - var n: MyEmptyType {} // expected-error{{getter with uninhabited return type 'MyEmptyType' is missing call to another never-returning function on all paths}} + var i: Int {} // expected-error{{missing return in getter for property expected to return 'Int'}} + var n: MyEmptyType {} // expected-error{{getter for property with uninhabited return type 'MyEmptyType' is missing call to another never-returning function on all paths}} static subscript(root: MyEmptyType) -> A {} subscript(_ e: MyEmptyType) -> Int {} subscript(_ e: MyEmptyType) -> T {} - subscript(_ i: Int) -> Int {} // expected-error{{missing return in getter expected to return 'Int'}} - subscript(_ p: Int) -> T {} // expected-error{{missing return in getter expected to return 'T'}} - subscript(_ i: Int) -> Self {} // expected-error{{getter with uninhabited return type 'MyEmptyType' is missing call to another never-returning function on all paths}} + subscript(_ i: Int) -> Int {} // expected-error{{missing return in getter for subscript expected to return 'Int'}} + subscript(_ p: Int) -> T {} // expected-error{{missing return in getter for subscript expected to return 'T'}} + subscript(_ i: Int) -> Self {} // expected-error{{getter for subscript with uninhabited return type 'MyEmptyType' is missing call to another never-returning function on all paths}} subscript(_ s: Self) -> Self {} static func unreachable_static_implicit_return(_ e: MyEmptyType) -> Int {} @@ -97,16 +97,16 @@ extension MyEmptyType { } extension Never { - var i: Int {} // expected-error{{missing return in getter expected to return 'Int'}} - var n: Never {} // expected-error{{getter with uninhabited return type 'Never' is missing call to another never-returning function on all paths}} + var i: Int {} // expected-error{{missing return in getter for property expected to return 'Int'}} + var n: Never {} // expected-error{{getter for property with uninhabited return type 'Never' is missing call to another never-returning function on all paths}} static subscript(root: Never) -> A {} subscript(_ n: Never) -> Int {} subscript(_ e: Never) -> T {} - subscript(_ i: Int) -> Int {} // expected-error{{missing return in getter expected to return 'Int'}} - subscript(_ p: Int) -> T {} // expected-error{{missing return in getter expected to return 'T'}} - subscript(_ i: Int) -> Self {} // expected-error{{getter with uninhabited return type 'Never' is missing call to another never-returning function on all paths}} + subscript(_ i: Int) -> Int {} // expected-error{{missing return in getter for subscript expected to return 'Int'}} + subscript(_ p: Int) -> T {} // expected-error{{missing return in getter for subscript expected to return 'T'}} + subscript(_ i: Int) -> Self {} // expected-error{{getter for subscript with uninhabited return type 'Never' is missing call to another never-returning function on all paths}} subscript(_ s: Self) -> Self {} static func unreachable_static_implicit_return(_ n: Never) -> Int {} @@ -128,8 +128,8 @@ enum InhabitedType { subscript(_ v: MyEmptyType, e: Int) -> Never {} // Inhabited params - subscript(_ i: Int) -> Int {} // expected-error{{missing return in getter expected to return 'Int'}} + subscript(_ i: Int) -> Int {} // expected-error{{missing return in getter for subscript expected to return 'Int'}} subscript(_ j: Int) -> Void {} - subscript(_ k: Int) -> Never {} // expected-error{{getter with uninhabited return type 'Never' is missing call to another never-returning function on all paths}} + subscript(_ k: Int) -> Never {} // expected-error{{getter for subscript with uninhabited return type 'Never' is missing call to another never-returning function on all paths}} // FIXME: ^ this diagnostic should probably use the word 'subscript' rather than 'getter' } diff --git a/test/SILOptimizer/return.swift b/test/SILOptimizer/return.swift index 84147017d6506..863b34349110c 100644 --- a/test/SILOptimizer/return.swift +++ b/test/SILOptimizer/return.swift @@ -232,14 +232,14 @@ struct S_56857 { if b { return 0 } - } // expected-error {{missing return in getter expected to return 'Int'}} + } // expected-error {{missing return in getter for property expected to return 'Int'}} var y: Int { get { if b { return 0 } - } // expected-error {{missing return in getter expected to return 'Int'}} + } // expected-error {{missing return in getter for property expected to return 'Int'}} set {} } } diff --git a/test/Serialization/caller_isolation_inherit.swift b/test/Serialization/caller_isolation_inherit.swift index a6d3b23442998..632d746f549ae 100644 --- a/test/Serialization/caller_isolation_inherit.swift +++ b/test/Serialization/caller_isolation_inherit.swift @@ -32,7 +32,7 @@ actor A { func test1a() async { await WithFeature.unspecifiedAsyncConcurrent(ns) // expected-error @-1 {{sending 'self.ns' risks causing data races}} - // expected-note @-2 {{sending 'self'-isolated 'self.ns' to nonisolated global function 'unspecifiedAsyncConcurrent' risks causing data races between nonisolated and 'self'-isolated uses}} + // expected-note @-2 {{sending 'self'-isolated 'self.ns' to @concurrent global function 'unspecifiedAsyncConcurrent' risks causing data races between @concurrent and 'self'-isolated uses}} } // CHECK-LABEL: // unspecifiedAsyncCaller(_:) @@ -48,7 +48,7 @@ actor A { func test2() async { await WithoutFeature.unspecifiedAsync(ns) // expected-error @-1 {{sending 'self.ns' risks causing data races}} - // expected-note @-2 {{sending 'self'-isolated 'self.ns' to nonisolated global function 'unspecifiedAsync' risks causing data races between nonisolated and 'self'-isolated uses}} + // expected-note @-2 {{sending 'self'-isolated 'self.ns' to @concurrent global function 'unspecifiedAsync' risks causing data races between @concurrent and 'self'-isolated uses}} } // CHECK-LABEL: // unspecifiedAsyncConcurrent(_:) @@ -59,7 +59,7 @@ actor A { // an error. await WithoutFeature.unspecifiedAsyncConcurrent(ns) // expected-error @-1 {{sending 'self.ns' risks causing data races}} - // expected-note @-2 {{sending 'self'-isolated 'self.ns' to nonisolated global function 'unspecifiedAsyncConcurrent' risks causing data races between nonisolated and 'self'-isolated uses}} + // expected-note @-2 {{sending 'self'-isolated 'self.ns' to @concurrent global function 'unspecifiedAsyncConcurrent' risks causing data races between @concurrent and 'self'-isolated uses}} } // CHECK-LABEL: // unspecifiedAsyncCaller(_:) @@ -82,7 +82,7 @@ actor A { func test3a() async { await WithFeature.nonisolatedAsyncConcurrent(ns) // expected-error @-1 {{sending 'self.ns' risks causing data races}} - // expected-note @-2 {{sending 'self'-isolated 'self.ns' to nonisolated global function 'nonisolatedAsyncConcurrent' risks causing data races between nonisolated and 'self'-isolated uses}} + // expected-note @-2 {{sending 'self'-isolated 'self.ns' to @concurrent global function 'nonisolatedAsyncConcurrent' risks causing data races between @concurrent and 'self'-isolated uses}} } // CHECK-LABEL: // nonisolatedAsyncCaller(_:) @@ -98,7 +98,7 @@ actor A { func test4() async { await WithoutFeature.nonisolatedAsync(ns) // expected-error @-1 {{sending 'self.ns' risks causing data races}} - // expected-note @-2 {{sending 'self'-isolated 'self.ns' to nonisolated global function 'nonisolatedAsync' risks causing data races between nonisolated and 'self'-isolated uses}} + // expected-note @-2 {{sending 'self'-isolated 'self.ns' to @concurrent global function 'nonisolatedAsync' risks causing data races between @concurrent and 'self'-isolated uses}} } // CHECK-LABEL: // nonisolatedAsyncConcurrent(_:) @@ -107,7 +107,7 @@ actor A { func test4a() async { await WithoutFeature.nonisolatedAsyncConcurrent(ns) // expected-error @-1 {{sending 'self.ns' risks causing data races}} - // expected-note @-2 {{sending 'self'-isolated 'self.ns' to nonisolated global function 'nonisolatedAsyncConcurrent' risks causing data races between nonisolated and 'self'-isolated uses}} + // expected-note @-2 {{sending 'self'-isolated 'self.ns' to @concurrent global function 'nonisolatedAsyncConcurrent' risks causing data races between @concurrent and 'self'-isolated uses}} } // CHECK-LABEL: // nonisolatedAsyncCaller(_:) @@ -132,7 +132,7 @@ actor A { let s = WithFeature.S() await s.unspecifiedAsyncConcurrent(ns) // expected-error @-1 {{sending 'self.ns' risks causing data races}} - // expected-note @-2 {{sending 'self'-isolated 'self.ns' to nonisolated instance method 'unspecifiedAsyncConcurrent' risks causing data races between nonisolated and 'self'-isolated uses}} + // expected-note @-2 {{sending 'self'-isolated 'self.ns' to @concurrent instance method 'unspecifiedAsyncConcurrent' risks causing data races between @concurrent and 'self'-isolated uses}} } // CHECK-LABEL: // S.unspecifiedAsyncCaller(_:) @@ -158,7 +158,7 @@ actor A { let s = WithFeature.S() await s.nonisolatedAsyncConcurrent(ns) // expected-error @-1 {{sending 'self.ns' risks causing data races}} - // expected-note @-2 {{sending 'self'-isolated 'self.ns' to nonisolated instance method 'nonisolatedAsyncConcurrent' risks causing data races between nonisolated and 'self'-isolated uses}} + // expected-note @-2 {{sending 'self'-isolated 'self.ns' to @concurrent instance method 'nonisolatedAsyncConcurrent' risks causing data races between @concurrent and 'self'-isolated uses}} } // CHECK-LABEL: // S.nonisolatedAsyncCaller(_:) @@ -176,7 +176,7 @@ actor A { let s = WithoutFeature.S() await s.unspecifiedAsync(ns) // expected-error @-1 {{sending 'self.ns' risks causing data races}} - // expected-note @-2 {{sending 'self'-isolated 'self.ns' to nonisolated instance method 'unspecifiedAsync' risks causing data races between nonisolated and 'self'-isolated uses}} + // expected-note @-2 {{sending 'self'-isolated 'self.ns' to @concurrent instance method 'unspecifiedAsync' risks causing data races between @concurrent and 'self'-isolated uses}} } // CHECK-LABEL: // S.unspecifiedAsyncConcurrent(_:) @@ -186,7 +186,7 @@ actor A { let s = WithoutFeature.S() await s.unspecifiedAsyncConcurrent(ns) // expected-error @-1 {{sending 'self.ns' risks causing data races}} - // expected-note @-2 {{sending 'self'-isolated 'self.ns' to nonisolated instance method 'unspecifiedAsyncConcurrent' risks causing data races between nonisolated and 'self'-isolated uses}} + // expected-note @-2 {{sending 'self'-isolated 'self.ns' to @concurrent instance method 'unspecifiedAsyncConcurrent' risks causing data races between @concurrent and 'self'-isolated uses}} } // CHECK-LABEL: // S.unspecifiedAsyncCaller(_:) @@ -204,7 +204,7 @@ actor A { let s = WithoutFeature.S() await s.nonisolatedAsync(ns) // expected-error @-1 {{sending 'self.ns' risks causing data races}} - // expected-note @-2 {{sending 'self'-isolated 'self.ns' to nonisolated instance method 'nonisolatedAsync' risks causing data races between nonisolated and 'self'-isolated uses}} + // expected-note @-2 {{sending 'self'-isolated 'self.ns' to @concurrent instance method 'nonisolatedAsync' risks causing data races between @concurrent and 'self'-isolated uses}} } // CHECK-LABEL: // S.nonisolatedAsyncConcurrent(_:) @@ -214,7 +214,7 @@ actor A { let s = WithoutFeature.S() await s.nonisolatedAsyncConcurrent(ns) // expected-error @-1 {{sending 'self.ns' risks causing data races}} - // expected-note @-2 {{sending 'self'-isolated 'self.ns' to nonisolated instance method 'nonisolatedAsyncConcurrent' risks causing data races between nonisolated and 'self'-isolated uses}} + // expected-note @-2 {{sending 'self'-isolated 'self.ns' to @concurrent instance method 'nonisolatedAsyncConcurrent' risks causing data races between @concurrent and 'self'-isolated uses}} } // CHECK-LABEL: // S.nonisolatedAsyncCaller(_:)