mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[SE-0470] Track the potential introduction of isolated conformances in regions
When we introduce isolation due to a (potential) isolated conformance, keep track of the protocol to which the conformance could be introduced. Use this information for two reasons: 1. Downgrade the error to a warning in Swift < 7, because we are newly diagnosing these 2. Add a note indicating where the isolated conformance could be introduced.
This commit is contained in:
@@ -1098,6 +1098,10 @@ NOTE(regionbasedisolation_typed_sendneversendable_via_arg_callee, none,
|
||||
"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",
|
||||
(const ValueDecl *))
|
||||
|
||||
// Error that is only used when the send non sendable emitter cannot discover any
|
||||
// information to give a better diagnostic.
|
||||
ERROR(regionbasedisolation_task_or_actor_isolated_sent, none,
|
||||
|
||||
@@ -190,7 +190,7 @@ public:
|
||||
NonisolatedNonsendingTaskIsolated = 0x4,
|
||||
|
||||
/// The maximum number of bits used by a Flag.
|
||||
MaxNumBits = 2,
|
||||
MaxNumBits = 3,
|
||||
};
|
||||
|
||||
using Options = OptionSet<Flag>;
|
||||
@@ -208,13 +208,19 @@ private:
|
||||
/// derived isolatedValue from.
|
||||
ActorInstance actorInstance;
|
||||
|
||||
/// When the isolation is introduced due to a (potentially) isolated
|
||||
/// conformance, the protocol whose conformance might be isolated.
|
||||
ProtocolDecl *isolatedConformance = nullptr;
|
||||
|
||||
unsigned kind : 8;
|
||||
unsigned options : 8;
|
||||
|
||||
SILIsolationInfo(SILValue isolatedValue, SILValue actorInstance,
|
||||
ActorIsolation actorIsolation, Options options = Options())
|
||||
ActorIsolation actorIsolation, Options options = Options(),
|
||||
ProtocolDecl *isolatedConformance = nullptr)
|
||||
: actorIsolation(actorIsolation), isolatedValue(isolatedValue),
|
||||
actorInstance(ActorInstance::getForValue(actorInstance)), kind(Actor),
|
||||
actorInstance(ActorInstance::getForValue(actorInstance)),
|
||||
isolatedConformance(isolatedConformance), kind(Actor),
|
||||
options(options.toRaw()) {
|
||||
assert((!actorInstance ||
|
||||
(actorIsolation.getKind() == ActorIsolation::ActorInstance &&
|
||||
@@ -226,15 +232,20 @@ private:
|
||||
}
|
||||
|
||||
SILIsolationInfo(SILValue isolatedValue, ActorInstance actorInstance,
|
||||
ActorIsolation actorIsolation, Options options = Options())
|
||||
ActorIsolation actorIsolation, Options options = Options(),
|
||||
ProtocolDecl *isolatedConformance = nullptr)
|
||||
: actorIsolation(actorIsolation), isolatedValue(isolatedValue),
|
||||
actorInstance(actorInstance), kind(Actor), options(options.toRaw()) {
|
||||
actorInstance(actorInstance), isolatedConformance(isolatedConformance),
|
||||
kind(Actor), options(options.toRaw())
|
||||
{
|
||||
assert(actorInstance);
|
||||
assert(actorIsolation.getKind() == ActorIsolation::ActorInstance);
|
||||
}
|
||||
|
||||
SILIsolationInfo(Kind kind, SILValue isolatedValue)
|
||||
: actorIsolation(), isolatedValue(isolatedValue), kind(kind), options(0) {
|
||||
SILIsolationInfo(Kind kind, SILValue isolatedValue,
|
||||
ProtocolDecl *isolatedConformance = nullptr)
|
||||
: actorIsolation(), isolatedValue(isolatedValue),
|
||||
isolatedConformance(isolatedConformance), kind(kind), options(0) {
|
||||
}
|
||||
|
||||
SILIsolationInfo(Kind kind, Options options = Options())
|
||||
@@ -261,6 +272,12 @@ public:
|
||||
return getOptions().contains(Flag::UnsafeNonIsolated);
|
||||
}
|
||||
|
||||
// Retrieve the protocol to which there is (or could be) an isolated
|
||||
// conformance.
|
||||
ProtocolDecl *getIsolatedConformance() const {
|
||||
return isolatedConformance;
|
||||
}
|
||||
|
||||
SILIsolationInfo withUnsafeNonIsolated(bool newValue = true) const {
|
||||
assert(*this && "Cannot be unknown");
|
||||
auto self = *this;
|
||||
@@ -292,6 +309,26 @@ public:
|
||||
return self;
|
||||
}
|
||||
|
||||
/// Produce a new isolation info value that merges in the given isolated
|
||||
/// conformance value.
|
||||
///
|
||||
/// If both isolation infos have an isolation conformance, pick one
|
||||
/// arbitrarily. Otherwise, the result has no isolated conformance.
|
||||
SILIsolationInfo
|
||||
withMergedIsolatedConformance(ProtocolDecl *newIsolatedConformance) const {
|
||||
SILIsolationInfo result(*this);
|
||||
if (!isolatedConformance || !newIsolatedConformance) {
|
||||
result.isolatedConformance = nullptr;
|
||||
return result;
|
||||
}
|
||||
|
||||
result.isolatedConformance =
|
||||
ProtocolDecl::compare(isolatedConformance, newIsolatedConformance) <= 0
|
||||
? isolatedConformance
|
||||
: newIsolatedConformance;
|
||||
return result;
|
||||
}
|
||||
|
||||
/// 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.
|
||||
@@ -458,10 +495,13 @@ public:
|
||||
Flag::UnappliedIsolatedAnyParameter};
|
||||
}
|
||||
|
||||
static SILIsolationInfo getGlobalActorIsolated(SILValue value,
|
||||
Type globalActorType) {
|
||||
static SILIsolationInfo getGlobalActorIsolated(
|
||||
SILValue value,
|
||||
Type globalActorType,
|
||||
ProtocolDecl *isolatedConformance = nullptr) {
|
||||
return {value, SILValue() /*no actor instance*/,
|
||||
ActorIsolation::forGlobalActor(globalActorType)};
|
||||
ActorIsolation::forGlobalActor(globalActorType),
|
||||
Options(), isolatedConformance};
|
||||
}
|
||||
|
||||
static SILIsolationInfo getGlobalActorIsolated(SILValue value,
|
||||
@@ -473,8 +513,9 @@ public:
|
||||
isolation.getGlobalActor());
|
||||
}
|
||||
|
||||
static SILIsolationInfo getTaskIsolated(SILValue value) {
|
||||
return {Kind::Task, value};
|
||||
static SILIsolationInfo getTaskIsolated(
|
||||
SILValue value, ProtocolDecl *isolatedConformance = nullptr) {
|
||||
return {Kind::Task, value, isolatedConformance};
|
||||
}
|
||||
|
||||
/// Attempt to infer the isolation region info for \p inst.
|
||||
|
||||
@@ -297,6 +297,9 @@ static SILIsolationInfo getIsolationForCastConformances(
|
||||
|
||||
const auto &destLayout = destType.getExistentialLayout();
|
||||
for (auto proto : destLayout.getProtocols()) {
|
||||
if (proto->isMarkerProtocol())
|
||||
continue;
|
||||
|
||||
// If the source type already conforms to the protocol, we won't be looking
|
||||
// it up dynamically.
|
||||
if (!lookupConformance(sourceType, proto, /*allowMissing=*/false).isInvalid())
|
||||
@@ -313,12 +316,12 @@ static SILIsolationInfo getIsolationForCastConformances(
|
||||
// Otherwise, it's task-isolated.
|
||||
if (functionIsolation && functionIsolation->isGlobalActor()) {
|
||||
return SILIsolationInfo::getGlobalActorIsolated(
|
||||
value, functionIsolation->getGlobalActor());
|
||||
value, functionIsolation->getGlobalActor(), proto);
|
||||
}
|
||||
|
||||
// Consider the cast to be task-isolated, because the runtime could find
|
||||
// a conformance that is isolated to the current context.
|
||||
return SILIsolationInfo::getTaskIsolated(value);
|
||||
return SILIsolationInfo::getTaskIsolated(value, proto);
|
||||
}
|
||||
|
||||
return {};
|
||||
@@ -4131,6 +4134,9 @@ SILIsolationInfo
|
||||
PartitionOpTranslator::getIsolationFromConformances(
|
||||
SILValue value, ArrayRef<ProtocolConformanceRef> conformances) {
|
||||
for (auto conformance: conformances) {
|
||||
if (conformance.getProtocol()->isMarkerProtocol())
|
||||
continue;
|
||||
|
||||
// If the conformance is a pack, recurse.
|
||||
if (conformance.isPack()) {
|
||||
auto pack = conformance.getPack();
|
||||
@@ -4149,7 +4155,7 @@ PartitionOpTranslator::getIsolationFromConformances(
|
||||
auto isolation = conformance.getConcrete()->getIsolation();
|
||||
if (isolation.isGlobalActor()) {
|
||||
return SILIsolationInfo::getGlobalActorIsolated(
|
||||
value, isolation.getGlobalActor());
|
||||
value, isolation.getGlobalActor(), conformance.getProtocol());
|
||||
}
|
||||
|
||||
continue;
|
||||
@@ -4164,7 +4170,8 @@ PartitionOpTranslator::getIsolationFromConformances(
|
||||
if (sendableMetatype &&
|
||||
lookupConformance(conformance.getType(), sendableMetatype,
|
||||
/*allowMissing=*/false).isInvalid()) {
|
||||
return SILIsolationInfo::getTaskIsolated(value);
|
||||
return SILIsolationInfo::getTaskIsolated(value,
|
||||
conformance.getProtocol());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4175,7 +4182,7 @@ PartitionOpTranslator::getIsolationFromConformances(
|
||||
TranslationSemantics
|
||||
PartitionOpTranslator::visitInitExistentialAddrInst(InitExistentialAddrInst *ieai) {
|
||||
auto conformanceIsolationInfo = getIsolationFromConformances(
|
||||
ieai->getResult(0), ieai->getConformances());
|
||||
ieai, ieai->getConformances());
|
||||
|
||||
translateSILMultiAssign(ieai->getResults(),
|
||||
makeOperandRefRange(ieai->getAllOperands()),
|
||||
@@ -4187,7 +4194,7 @@ PartitionOpTranslator::visitInitExistentialAddrInst(InitExistentialAddrInst *iea
|
||||
TranslationSemantics
|
||||
PartitionOpTranslator::visitInitExistentialRefInst(InitExistentialRefInst *ieri) {
|
||||
auto conformanceIsolationInfo = getIsolationFromConformances(
|
||||
ieri->getResult(0), ieri->getConformances());
|
||||
ieri, ieri->getConformances());
|
||||
|
||||
translateSILMultiAssign(ieri->getResults(),
|
||||
makeOperandRefRange(ieri->getAllOperands()),
|
||||
@@ -4199,7 +4206,7 @@ PartitionOpTranslator::visitInitExistentialRefInst(InitExistentialRefInst *ieri)
|
||||
TranslationSemantics
|
||||
PartitionOpTranslator::visitInitExistentialValueInst(InitExistentialValueInst *ievi) {
|
||||
auto conformanceIsolationInfo = getIsolationFromConformances(
|
||||
ievi->getResult(0), ievi->getConformances());
|
||||
ievi, ievi->getConformances());
|
||||
|
||||
translateSILMultiAssign(ievi->getResults(),
|
||||
makeOperandRefRange(ievi->getAllOperands()),
|
||||
|
||||
@@ -1312,6 +1312,18 @@ public:
|
||||
~SendNeverSentDiagnosticEmitter() {
|
||||
if (!emittedErrorDiagnostic) {
|
||||
emitUnknownPatternError();
|
||||
} else if (auto proto = isolationRegionInfo.getIsolationInfo()
|
||||
.getIsolatedConformance()) {
|
||||
// If the diagnostic comes from a (potentially) isolated conformance,
|
||||
// add a note saying so and indicating where the isolated conformance
|
||||
// can come in.
|
||||
if (auto value = isolationRegionInfo.getIsolationInfo().getIsolatedValue()) {
|
||||
if (auto loc = value.getLoc()) {
|
||||
diagnoseNote(
|
||||
loc, diag::regionbasedisolation_isolated_conformance_introduced,
|
||||
proto);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1326,6 +1338,13 @@ public:
|
||||
}
|
||||
|
||||
std::optional<DiagnosticBehavior> getBehaviorLimit() const {
|
||||
// If the failure is due to an isolated conformance, downgrade the error
|
||||
// to a warning prior to Swift 7.
|
||||
if (isolationRegionInfo.getIsolationInfo().getIsolatedConformance() &&
|
||||
!sendingOperand->get()->getType().getASTType()->getASTContext().LangOpts
|
||||
.isSwiftVersionAtLeast(7))
|
||||
return DiagnosticBehavior::Warning;
|
||||
|
||||
return sendingOperand->get()->getType().getConcurrencyDiagnosticBehavior(
|
||||
getOperand()->getFunction());
|
||||
}
|
||||
@@ -1577,8 +1596,7 @@ public:
|
||||
getIsolationRegionInfo().printForDiagnostics(getFunction());
|
||||
|
||||
diagnoseNote(loc, diag::regionbasedisolation_named_send_nt_asynclet_capture,
|
||||
name, descriptiveKindStr)
|
||||
.limitBehaviorIf(getBehaviorLimit());
|
||||
name, descriptiveKindStr);
|
||||
}
|
||||
|
||||
void emitNamedIsolation(SILLocation loc, Identifier name,
|
||||
|
||||
@@ -1070,6 +1070,10 @@ SILIsolationInfo SILIsolationInfo::get(SILArgument *arg) {
|
||||
}
|
||||
|
||||
void SILIsolationInfo::printOptions(llvm::raw_ostream &os) const {
|
||||
if (isolatedConformance) {
|
||||
os << "isolated-conformance-to(" << isolatedConformance->getName() << ")";
|
||||
}
|
||||
|
||||
auto opts = getOptions();
|
||||
if (!opts)
|
||||
return;
|
||||
@@ -1255,9 +1259,11 @@ void SILIsolationInfo::Profile(llvm::FoldingSetNodeID &id) const {
|
||||
return;
|
||||
case Task:
|
||||
id.AddPointer(getIsolatedValue());
|
||||
id.AddPointer(getIsolatedConformance());
|
||||
return;
|
||||
case Actor:
|
||||
id.AddPointer(getIsolatedValue());
|
||||
id.AddPointer(getIsolatedConformance());
|
||||
getActorIsolation().Profile(id);
|
||||
return;
|
||||
}
|
||||
@@ -1570,7 +1576,7 @@ SILDynamicMergedIsolationInfo::merge(SILIsolationInfo other) const {
|
||||
// If both innerInfo and other have the same isolation, we are obviously
|
||||
// done. Just return innerInfo since we could return either.
|
||||
if (innerInfo.hasSameIsolation(other))
|
||||
return {innerInfo};
|
||||
return {innerInfo.withMergedIsolatedConformance(other.getIsolatedConformance())};
|
||||
|
||||
// Ok, there is some difference in between innerInfo and other. Lets see if
|
||||
// they are both actor instance isolated and if either are unapplied
|
||||
@@ -1579,9 +1585,9 @@ SILDynamicMergedIsolationInfo::merge(SILIsolationInfo other) const {
|
||||
if (innerInfo.getActorIsolation().isActorInstanceIsolated() &&
|
||||
other.getActorIsolation().isActorInstanceIsolated()) {
|
||||
if (innerInfo.isUnappliedIsolatedAnyParameter())
|
||||
return other;
|
||||
return other.withMergedIsolatedConformance(innerInfo.getIsolatedConformance());
|
||||
if (other.isUnappliedIsolatedAnyParameter())
|
||||
return innerInfo;
|
||||
return innerInfo.withMergedIsolatedConformance(other.getIsolatedConformance());
|
||||
}
|
||||
|
||||
// Otherwise, they do not match... so return None to signal merge failure.
|
||||
@@ -1610,7 +1616,8 @@ SILDynamicMergedIsolationInfo::merge(SILIsolationInfo other) const {
|
||||
if (innerInfo.isTaskIsolated() && other.isTaskIsolated()) {
|
||||
if (innerInfo.isNonisolatedNonsendingTaskIsolated() ||
|
||||
other.isNonisolatedNonsendingTaskIsolated())
|
||||
return other.withNonisolatedNonsendingTaskIsolated(true);
|
||||
return other.withNonisolatedNonsendingTaskIsolated(true)
|
||||
.withMergedIsolatedConformance(innerInfo.getIsolatedConformance());
|
||||
}
|
||||
|
||||
// Otherwise, just return other.
|
||||
|
||||
@@ -120,20 +120,21 @@ func acceptSendingAnyObjectR(_ s: sending AnyObject & R) { }
|
||||
@MainActor func passSendingExistential<T: P, U: AnyObject & P , V: R, W: AnyObject & R>(
|
||||
t: sending T, u: sending U, v: sending V, w: sending W
|
||||
) {
|
||||
// FIXME: Diagnostics here should really mention that it's the main-actor-
|
||||
// isolated conformance to P that's the problem.
|
||||
acceptSendingP(S()) // expected-error{{sending value of non-Sendable type 'S' risks causing data races}}
|
||||
acceptSendingP(S()) // expected-warning{{sending value of non-Sendable type 'S' risks causing data races}}
|
||||
// expected-note@-1{{Passing main actor-isolated value of non-Sendable type 'S' as a 'sending' parameter to global function 'acceptSendingP' risks causing races}}
|
||||
acceptSendingP(SC()) // expected-error{{sending value of non-Sendable type 'SC'}}
|
||||
// expected-note@-2{{isolated conformance to protocol 'P' can be introduced here}}
|
||||
acceptSendingP(SC()) // expected-warning{{sending value of non-Sendable type 'SC'}}
|
||||
// expected-note@-1{{Passing main actor-isolated value of non-Sendable type 'SC' as a 'sending' parameter to global function 'acceptSendingP' risks causing races}}' risks causing data races}}
|
||||
acceptSendingAnyObjectP(SC()) // expected-error{{sending value of non-Sendable type 'SC' risks causing data races}}
|
||||
// expected-note@-2{{isolated conformance to protocol 'P' can be introduced here}}
|
||||
acceptSendingAnyObjectP(SC()) // expected-warning{{sending value of non-Sendable type 'SC' risks causing data races}}
|
||||
// expected-note@-1{{Passing main actor-isolated value of non-Sendable type 'SC' as a 'sending' parameter to global function 'acceptSendingAnyObjectP' risks causing races}}' risks causing data races}}
|
||||
|
||||
acceptSendingP(t) // expected-error{{sending 't' risks causing data races}}
|
||||
// expected-note@-2{{isolated conformance to protocol 'P' can be introduced here}}
|
||||
acceptSendingP(t) // expected-warning{{sending 't' risks causing data races}}
|
||||
// expected-note@-1{{task-isolated 't' is passed as a 'sending' parameter; Uses in callee may race with later task-isolated uses}}
|
||||
acceptSendingAnyObjectP(u) // expected-error{{sending value of non-Sendable type 'U' risks causing data races}}
|
||||
// expected-note@-2{{isolated conformance to protocol 'P' can be introduced he}}
|
||||
acceptSendingAnyObjectP(u) // expected-warning{{sending value of non-Sendable type 'U' risks causing data races}}
|
||||
// expected-note@-1{{task-isolated value of non-Sendable type 'U'}}
|
||||
|
||||
// expected-note@-2{{isolated conformance to protocol 'P' can be introduced here}}
|
||||
// All of these are okay, because there are no isolated conformances to R.
|
||||
acceptSendingR(S())
|
||||
acceptSendingR(SC())
|
||||
@@ -146,16 +147,15 @@ func dynamicCastingExistential(
|
||||
_ s1: sending Any,
|
||||
_ s2: sending Any
|
||||
) {
|
||||
// TODO: Improve diagnostics due to isolated conformances.
|
||||
if let s1p = s1 as? any P {
|
||||
acceptSendingP(s1p) // expected-error{{sending 's1p' risks causing data races}}
|
||||
if let s1p = s1 as? any P { // expected-note{{isolated conformance to protocol 'P' can be introduced here}}
|
||||
acceptSendingP(s1p) // expected-warning{{sending 's1p' risks causing data races}}
|
||||
// expected-note@-1{{task-isolated 's1p' is passed as a 'sending' parameter; Uses in callee may race with later task-isolated uses}}
|
||||
} else {
|
||||
print(s1)
|
||||
}
|
||||
|
||||
if let s2p = s2 as? any AnyObject & P {
|
||||
acceptSendingAnyObjectP(s2p) // expected-error{{sending 's2p' risks causing data races}}
|
||||
if let s2p = s2 as? any AnyObject & P { // expected-note{{isolated conformance to protocol 'P' can be introduced here}}
|
||||
acceptSendingAnyObjectP(s2p) // expected-warning{{sending 's2p' risks causing data races}}
|
||||
// expected-note@-1{{task-isolated 's2p' is passed as a 'sending' parameter; Uses in callee may race with later task-isolated uses}}
|
||||
} else {
|
||||
print(s2)
|
||||
@@ -185,16 +185,15 @@ func dynamicCastingGeneric(
|
||||
_ s1: sending some Any,
|
||||
_ s2: sending some Any
|
||||
) {
|
||||
// TODO: Improve diagnostics due to isolated conformances.
|
||||
if let s1p = s1 as? any P {
|
||||
acceptSendingP(s1p) // expected-error{{sending 's1p' risks causing data races}}
|
||||
if let s1p = s1 as? any P { // expected-note{{isolated conformance to protocol 'P' can be introduced here}}
|
||||
acceptSendingP(s1p) // expected-warning{{sending 's1p' risks causing data races}}
|
||||
// expected-note@-1{{task-isolated 's1p' is passed as a 'sending' parameter; Uses in callee may race with later task-isolated uses}}
|
||||
} else {
|
||||
print(s1)
|
||||
}
|
||||
|
||||
if let s2p = s2 as? any AnyObject & P {
|
||||
acceptSendingAnyObjectP(s2p) // expected-error{{sending 's2p' risks causing data races}}
|
||||
if let s2p = s2 as? any AnyObject & P { // expected-note{{isolated conformance to protocol 'P' can be introduced here}}
|
||||
acceptSendingAnyObjectP(s2p) // expected-warning{{sending 's2p' risks causing data races}}
|
||||
// expected-note@-1{{task-isolated 's2p' is passed as a 'sending' parameter; Uses in callee may race with later task-isolated uses}}
|
||||
} else {
|
||||
print(s2)
|
||||
@@ -239,12 +238,12 @@ func forceCastingExistential(
|
||||
_ s1: sending Any,
|
||||
_ s2: sending AnyObject
|
||||
) {
|
||||
let s1p = s1 as! any P
|
||||
acceptSendingP(s1p) // expected-error{{sending 's1p' risks causing data races}}
|
||||
let s1p = s1 as! any P // expected-note{{isolated conformance to protocol 'P' can be introduced here}}
|
||||
acceptSendingP(s1p) // expected-warning{{sending 's1p' risks causing data races}}
|
||||
// expected-note@-1{{task-isolated 's1p' is passed as a 'sending' parameter; Uses in callee may race with later task-isolated uses}}
|
||||
|
||||
let s2p = s2 as! any AnyObject & P
|
||||
acceptSendingAnyObjectP(s2p) // expected-error{{sending 's2p' risks causing data races}}
|
||||
let s2p = s2 as! any AnyObject & P // expected-note{{isolated conformance to protocol 'P' can be introduced here}}
|
||||
acceptSendingAnyObjectP(s2p) // expected-warning{{sending 's2p' risks causing data races}}
|
||||
// expected-note@-1{{task-isolated 's2p' is passed as a 'sending' parameter; Uses in callee may race with later task-isolated uses}}
|
||||
}
|
||||
|
||||
@@ -263,12 +262,12 @@ func forceCastingGeneric(
|
||||
_ s1: sending some Any,
|
||||
_ s2: sending some AnyObject
|
||||
) {
|
||||
let s1p = s1 as! any P
|
||||
acceptSendingP(s1p) // expected-error{{sending 's1p' risks causing data races}}
|
||||
let s1p = s1 as! any P // expected-note{{isolated conformance to protocol 'P' can be introduced here}}
|
||||
acceptSendingP(s1p) // expected-warning{{sending 's1p' risks causing data races}}
|
||||
// expected-note@-1{{task-isolated 's1p' is passed as a 'sending' parameter; Uses in callee may race with later task-isolated uses}}
|
||||
|
||||
let s2p = s2 as! any AnyObject & P
|
||||
acceptSendingAnyObjectP(s2p) // expected-error{{sending 's2p' risks causing data races}}
|
||||
let s2p = s2 as! any AnyObject & P // expected-note{{isolated conformance to protocol 'P' can be introduced here}}
|
||||
acceptSendingAnyObjectP(s2p) // expected-warning{{sending 's2p' risks causing data races}}
|
||||
// expected-note@-1{{task-isolated 's2p' is passed as a 'sending' parameter; Uses in callee may race with later task-isolated uses}}
|
||||
}
|
||||
|
||||
@@ -276,12 +275,12 @@ func forceCastingGeneric(
|
||||
_ s1: sending some Any,
|
||||
_ s2: sending some AnyObject
|
||||
) {
|
||||
let s1p = s1 as! any P
|
||||
acceptSendingP(s1p) // expected-error{{sending 's1p' risks causing data races}}
|
||||
let s1p = s1 as! any P // expected-note{{isolated conformance to protocol 'P' can be introduced here}}
|
||||
acceptSendingP(s1p) // expected-warning{{sending 's1p' risks causing data races}}
|
||||
// expected-note@-1{{main actor-isolated 's1p' is passed as a 'sending' parameter; Uses in callee may race with later main actor-isolated uses}}
|
||||
|
||||
let s2p = s2 as! any AnyObject & P
|
||||
acceptSendingAnyObjectP(s2p) // expected-error{{sending 's2p' risks causing data races}}
|
||||
let s2p = s2 as! any AnyObject & P // expected-note{{isolated conformance to protocol 'P' can be introduced here}}
|
||||
acceptSendingAnyObjectP(s2p) // expected-warning{{sending 's2p' risks causing data races}}
|
||||
// expected-note@-1{{main actor-isolated 's2p' is passed as a 'sending' parameter; Uses in callee may race with later main actor-isolated uses}}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user