diff --git a/include/swift/ABI/MetadataValues.h b/include/swift/ABI/MetadataValues.h index f258ffcc7f5..c9ef96b4e52 100644 --- a/include/swift/ABI/MetadataValues.h +++ b/include/swift/ABI/MetadataValues.h @@ -313,6 +313,11 @@ enum class DynamicCastFlags : size_t { /// True if the cast should destroy the source value on failure; /// false if the value should be left in place. DestroyOnFailure = 0x4, + + /// True if the cast should prohibit the use of any isolated conformances, + /// for example because there is a Sendable constraint on the existential + /// type we're casting to. + ProhibitIsolatedConformances = 0x8, }; inline bool operator&(DynamicCastFlags a, DynamicCastFlags b) { return (size_t(a) & size_t(b)) != 0; diff --git a/lib/IRGen/GenCast.cpp b/lib/IRGen/GenCast.cpp index 22fd39ef9aa..b15002ea7a1 100644 --- a/lib/IRGen/GenCast.cpp +++ b/lib/IRGen/GenCast.cpp @@ -42,8 +42,11 @@ using namespace swift; using namespace irgen; /// Compute the flags to pass to swift_dynamicCast. -static DynamicCastFlags getDynamicCastFlags(CastConsumptionKind consumptionKind, - CheckedCastMode mode) { +static DynamicCastFlags getDynamicCastFlags( + CastConsumptionKind consumptionKind, + CheckedCastMode mode, + CastingIsolatedConformances isolatedConformances +) { DynamicCastFlags flags = DynamicCastFlags::Default; if (mode == CheckedCastMode::Unconditional) @@ -53,6 +56,14 @@ static DynamicCastFlags getDynamicCastFlags(CastConsumptionKind consumptionKind, if (shouldTakeOnSuccess(consumptionKind)) flags |= DynamicCastFlags::TakeOnSuccess; + switch (isolatedConformances) { + case CastingIsolatedConformances::Allow: + break; + case CastingIsolatedConformances::Prohibit: + flags |= DynamicCastFlags::ProhibitIsolatedConformances; + break; + } + return flags; } @@ -63,10 +74,12 @@ llvm::Value *irgen::emitCheckedCast(IRGenFunction &IGF, Address dest, CanType targetType, CastConsumptionKind consumptionKind, - CheckedCastMode mode) { + CheckedCastMode mode, + CastingIsolatedConformances isolatedConformances) { // TODO: attempt to specialize this based on the known types. - DynamicCastFlags flags = getDynamicCastFlags(consumptionKind, mode); + DynamicCastFlags flags = getDynamicCastFlags(consumptionKind, mode, + isolatedConformances); // Cast both addresses to opaque pointer type. dest = IGF.Builder.CreateElementBitCast(dest, IGF.IGM.OpaqueTy); @@ -847,6 +860,7 @@ void irgen::emitScalarCheckedCast(IRGenFunction &IGF, SILType targetLoweredType, CanType targetFormalType, CheckedCastMode mode, + CastingIsolatedConformances isolatedConformances, Explosion &out) { assert(sourceLoweredType.isObject()); assert(targetLoweredType.isObject()); @@ -976,7 +990,7 @@ void irgen::emitScalarCheckedCast(IRGenFunction &IGF, src, sourceFormalType, dest, targetFormalType, CastConsumptionKind::TakeAlways, - mode); + mode, isolatedConformances); llvm::Value *successResult = IGF.Builder.CreateLoad(dest); llvm::Value *failureResult = llvm::ConstantPointerNull::get(destPtrType); llvm::Value *result = IGF.Builder.CreateSelect(success, successResult, failureResult); diff --git a/lib/IRGen/GenCast.h b/lib/IRGen/GenCast.h index a9a8002fd25..3529b466709 100644 --- a/lib/IRGen/GenCast.h +++ b/lib/IRGen/GenCast.h @@ -28,6 +28,7 @@ namespace swift { class SILType; class ProtocolDecl; enum class CastConsumptionKind : unsigned char; + enum class CastingIsolatedConformances: uint8_t; namespace irgen { class Address; @@ -46,7 +47,8 @@ namespace irgen { Address dest, CanType toType, CastConsumptionKind consumptionKind, - CheckedCastMode mode); + CheckedCastMode mode, + CastingIsolatedConformances isolatedConformances); void emitScalarCheckedCast(IRGenFunction &IGF, Explosion &value, SILType sourceLoweredType, @@ -54,6 +56,7 @@ namespace irgen { SILType targetLoweredType, CanType targetFormalType, CheckedCastMode mode, + CastingIsolatedConformances isolatedConformances, Explosion &out); llvm::Value *emitFastClassCastIfPossible( diff --git a/lib/IRGen/IRGenSIL.cpp b/lib/IRGen/IRGenSIL.cpp index 086da5d307e..3aabe05c04b 100644 --- a/lib/IRGen/IRGenSIL.cpp +++ b/lib/IRGen/IRGenSIL.cpp @@ -7186,7 +7186,8 @@ visitUncheckedRefCastAddrInst(swift::UncheckedRefCastAddrInst *i) { src, i->getSourceFormalType(), dest, i->getTargetFormalType(), CastConsumptionKind::TakeAlways, - CheckedCastMode::Unconditional); + CheckedCastMode::Unconditional, + CastingIsolatedConformances::Allow); } void IRGenSILFunction::visitUncheckedAddrCastInst( @@ -7416,6 +7417,7 @@ void IRGenSILFunction::visitUnconditionalCheckedCastInst( i->getTargetLoweredType(), i->getTargetFormalType(), CheckedCastMode::Unconditional, + i->getIsolatedConformances(), ex); setLoweredExplosion(i, ex); } @@ -7604,7 +7606,8 @@ void IRGenSILFunction::visitUnconditionalCheckedCastAddrInst( src, i->getSourceFormalType(), dest, i->getTargetFormalType(), CastConsumptionKind::TakeAlways, - CheckedCastMode::Unconditional); + CheckedCastMode::Unconditional, + i->getIsolatedConformances()); } void IRGenSILFunction::visitCheckedCastBranchInst( @@ -7625,6 +7628,7 @@ void IRGenSILFunction::visitCheckedCastBranchInst( i->getTargetLoweredType(), i->getTargetFormalType(), CheckedCastMode::Conditional, + i->getIsolatedConformances(), ex); auto val = ex.claimNext(); castResult.casted = val; @@ -7662,7 +7666,8 @@ void IRGenSILFunction::visitCheckedCastAddrBranchInst( emitCheckedCast(*this, src, i->getSourceFormalType(), dest, i->getTargetFormalType(), - i->getConsumptionKind(), CheckedCastMode::Conditional); + i->getConsumptionKind(), CheckedCastMode::Conditional, + i->getIsolatedConformances()); Builder.CreateCondBr(castSucceeded, getLoweredBB(i->getSuccessBB()).bb, getLoweredBB(i->getFailureBB()).bb); diff --git a/stdlib/public/runtime/Casting.cpp b/stdlib/public/runtime/Casting.cpp index 8125662ebad..f495c03d0c0 100644 --- a/stdlib/public/runtime/Casting.cpp +++ b/stdlib/public/runtime/Casting.cpp @@ -614,12 +614,19 @@ bool swift::_conformsToProtocolInContext( const OpaqueValue *value, const Metadata *type, ProtocolDescriptorRef protocol, - const WitnessTable **conformance) { + const WitnessTable **conformance, + bool prohibitIsolatedConformances) { ConformanceExecutionContext context; if (!_conformsToProtocol(value, type, protocol, conformance, &context)) return false; + // If we aren't allowed to use isolated conformances and we ended up with + // one, fail. + if (prohibitIsolatedConformances && + context.globalActorIsolationType) + return false; + if (!swift_isInConformanceExecutionContext(type, &context)) return false; @@ -631,7 +638,8 @@ bool swift::_conformsToProtocolInContext( static bool _conformsToProtocols(const OpaqueValue *value, const Metadata *type, const ExistentialTypeMetadata *existentialType, - const WitnessTable **conformances) { + const WitnessTable **conformances, + bool prohibitIsolatedConformances) { if (auto *superclass = existentialType->getSuperclassConstraint()) { if (!swift_dynamicCastMetatype(type, superclass)) return false; @@ -644,7 +652,7 @@ static bool _conformsToProtocols(const OpaqueValue *value, for (auto protocol : existentialType->getProtocols()) { if (!_conformsToProtocolInContext( - value, type, protocol, conformances)) + value, type, protocol, conformances, prohibitIsolatedConformances)) return false; if (conformances != nullptr && protocol.needsWitnessTable()) { assert(*conformances != nullptr); @@ -1050,9 +1058,10 @@ swift_dynamicCastMetatypeImpl(const Metadata *sourceType, } static const Metadata * -swift_dynamicCastMetatypeUnconditionalImpl(const Metadata *sourceType, - const Metadata *targetType, - const char *file, unsigned line, unsigned column) { +swift_dynamicCastMetatypeUnconditionalImpl( + const Metadata *sourceType, + const Metadata *targetType, + const char *file, unsigned line, unsigned column) { auto origSourceType = sourceType; // Identical types always succeed @@ -1138,7 +1147,8 @@ swift_dynamicCastMetatypeUnconditionalImpl(const Metadata *sourceType, case MetadataKind::Existential: { auto targetTypeAsExistential = static_cast(targetType); - if (_conformsToProtocols(nullptr, sourceType, targetTypeAsExistential, nullptr)) + if (_conformsToProtocols(nullptr, sourceType, targetTypeAsExistential, + nullptr, /*prohibitIsolatedConformances=*/false)) return origSourceType; swift_dynamicCastFailure(sourceType, targetType); } diff --git a/stdlib/public/runtime/DynamicCast.cpp b/stdlib/public/runtime/DynamicCast.cpp index 237fc7e006d..f9aefd9489a 100644 --- a/stdlib/public/runtime/DynamicCast.cpp +++ b/stdlib/public/runtime/DynamicCast.cpp @@ -87,7 +87,7 @@ typedef DynamicCastResult (tryCastFunctionType)( OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *srcValue, const Metadata *srcType, const Metadata *&destFailureType, const Metadata *&srcFailureType, - bool takeOnSuccess, bool mayDeferChecks + bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances ); // Forward-declare the main top-level `tryCast()` function @@ -401,7 +401,7 @@ tryCastUnwrappingObjCSwiftValueSource( OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *srcValue, const Metadata *srcType, const Metadata *&destFailureType, const Metadata *&srcFailureType, - bool takeOnSuccess, bool mayDeferChecks) + bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances) { id srcObject; memcpy(&srcObject, srcValue, sizeof(id)); @@ -422,7 +422,7 @@ tryCastUnwrappingObjCSwiftValueSource( destLocation, destType, const_cast(srcInnerValue), srcInnerType, destFailureType, srcFailureType, - /*takeOnSuccess=*/ false, mayDeferChecks); + /*takeOnSuccess=*/ false, mayDeferChecks, prohibitIsolatedConformances); } #else static DynamicCastResult @@ -430,7 +430,7 @@ tryCastUnwrappingSwiftValueSource( OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *srcValue, const Metadata *srcType, const Metadata *&destFailureType, const Metadata *&srcFailureType, - bool takeOnSuccess, bool mayDeferChecks) + bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances) { assert(srcType->getKind() == MetadataKind::Class); @@ -452,7 +452,7 @@ tryCastToSwiftClass( OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *srcValue, const Metadata *srcType, const Metadata *&destFailureType, const Metadata *&srcFailureType, - bool takeOnSuccess, bool mayDeferChecks) + bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances) { assert(srcType != destType); assert(destType->getKind() == MetadataKind::Class); @@ -496,7 +496,7 @@ tryCastToObjectiveCClass( OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *srcValue, const Metadata *srcType, const Metadata *&destFailureType, const Metadata *&srcFailureType, - bool takeOnSuccess, bool mayDeferChecks) + bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances) { assert(srcType != destType); assert(destType->getKind() == MetadataKind::ObjCClassWrapper); @@ -546,7 +546,7 @@ tryCastToForeignClass( OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *srcValue, const Metadata *srcType, const Metadata *&destFailureType, const Metadata *&srcFailureType, - bool takeOnSuccess, bool mayDeferChecks) + bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances) { #if SWIFT_OBJC_INTEROP assert(srcType != destType); @@ -594,7 +594,8 @@ tryCastToForeignClass( static DynamicCastResult tryCastToForeignReferenceType( OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *srcValue, const Metadata *srcType, const Metadata *&destFailureType, - const Metadata *&srcFailureType, bool takeOnSuccess, bool mayDeferChecks) { + const Metadata *&srcFailureType, bool takeOnSuccess, bool mayDeferChecks, + bool prohibitIsolatedConformances) { assert(srcType != destType); assert(destType->getKind() == MetadataKind::ForeignReferenceType); @@ -610,7 +611,7 @@ tryCastToEnum( OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *srcValue, const Metadata *srcType, const Metadata *&destFailureType, const Metadata *&srcFailureType, - bool takeOnSuccess, bool mayDeferChecks) + bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances) { assert(srcType != destType); // Note: Optional is handled elsewhere @@ -783,7 +784,7 @@ tryCastToAnyHashable( OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *srcValue, const Metadata *srcType, const Metadata *&destFailureType, const Metadata *&srcFailureType, - bool takeOnSuccess, bool mayDeferChecks) + bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances) { assert(srcType != destType); assert(destType->getKind() == MetadataKind::Struct); @@ -859,7 +860,7 @@ tryCastToArray( OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *srcValue, const Metadata *srcType, const Metadata *&destFailureType, const Metadata *&srcFailureType, - bool takeOnSuccess, bool mayDeferChecks) + bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances) { assert(srcType != destType); assert(destType->getKind() == MetadataKind::Struct); @@ -899,7 +900,7 @@ tryCastToDictionary( OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *srcValue, const Metadata *srcType, const Metadata *&destFailureType, const Metadata *&srcFailureType, - bool takeOnSuccess, bool mayDeferChecks) + bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances) { assert(srcType != destType); assert(destType->getKind() == MetadataKind::Struct); @@ -940,7 +941,7 @@ tryCastToSet( OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *srcValue, const Metadata *srcType, const Metadata *&destFailureType, const Metadata *&srcFailureType, - bool takeOnSuccess, bool mayDeferChecks) + bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances) { assert(srcType != destType); assert(destType->getKind() == MetadataKind::Struct); @@ -982,7 +983,7 @@ tryCastToString( OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *srcValue, const Metadata *srcType, const Metadata *&destFailureType, const Metadata *&srcFailureType, - bool takeOnSuccess, bool mayDeferChecks) + bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances) { assert(srcType != destType); assert(destType->getKind() == MetadataKind::Struct); @@ -1013,7 +1014,7 @@ tryCastToStruct( OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *srcValue, const Metadata *srcType, const Metadata *&destFailureType, const Metadata *&srcFailureType, - bool takeOnSuccess, bool mayDeferChecks) + bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances) { assert(srcType != destType); assert(destType->getKind() == MetadataKind::Struct); @@ -1036,7 +1037,7 @@ tryCastToOptional( OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *srcValue, const Metadata *srcType, const Metadata *&destFailureType, const Metadata *&srcFailureType, - bool takeOnSuccess, bool mayDeferChecks) + bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances) { assert(srcType != destType); assert(destType->getKind() == MetadataKind::Optional); @@ -1110,7 +1111,7 @@ tryCastUnwrappingOptionalBoth( OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *srcValue, const Metadata *srcType, const Metadata *&destFailureType, const Metadata *&srcFailureType, - bool takeOnSuccess, bool mayDeferChecks) + bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances) { assert(destType->getKind() == MetadataKind::Optional); assert(srcType->getKind() == MetadataKind::Optional); @@ -1134,7 +1135,8 @@ tryCastUnwrappingOptionalBoth( auto destInnerLocation = destLocation; // Single-payload enum layout auto subcastResult = tryCast( destInnerLocation, destInnerType, srcValue, srcInnerType, - destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks, + prohibitIsolatedConformances); if (isSuccess(subcastResult)) { destInnerType->vw_storeEnumTagSinglePayload( destLocation, /*case*/ 0, /*emptyCases*/ 1); @@ -1153,7 +1155,7 @@ tryCastUnwrappingOptionalDestination( OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *srcValue, const Metadata *srcType, const Metadata *&destFailureType, const Metadata *&srcFailureType, - bool takeOnSuccess, bool mayDeferChecks) + bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances) { assert(destType->getKind() == MetadataKind::Optional); @@ -1162,7 +1164,8 @@ tryCastUnwrappingOptionalDestination( auto destInnerLocation = destLocation; // Single-payload enum layout auto subcastResult = tryCast( destInnerLocation, destInnerType, srcValue, srcType, - destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks, + prohibitIsolatedConformances); if (isSuccess(subcastResult)) { destInnerType->vw_storeEnumTagSinglePayload( destLocation, /*case*/ 0, /*emptyCases*/ 1); @@ -1179,7 +1182,7 @@ tryCastUnwrappingOptionalSource( OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *srcValue, const Metadata *srcType, const Metadata *&destFailureType, const Metadata *&srcFailureType, - bool takeOnSuccess, bool mayDeferChecks) + bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances) { assert(srcType->getKind() == MetadataKind::Optional); @@ -1190,7 +1193,8 @@ tryCastUnwrappingOptionalSource( if (nonNil) { // Recurse with unwrapped source return tryCast(destLocation, destType, srcValue, srcInnerType, - destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks, + prohibitIsolatedConformances); } return DynamicCastResult::Failure; } @@ -1208,7 +1212,7 @@ tryCastToTuple( OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *srcValue, const Metadata *srcType, const Metadata *&destFailureType, const Metadata *&srcFailureType, - bool takeOnSuccess, bool mayDeferChecks) + bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances) { assert(srcType != destType); assert(destType->getKind() == MetadataKind::Tuple); @@ -1284,7 +1288,8 @@ tryCastToTuple( auto subcastResult = tryCast(destElt.findIn(destLocation), destElt.Type, srcElt.findIn(srcValue), srcElt.Type, destFailureType, srcFailureType, - false, mayDeferChecks); + false, mayDeferChecks, + prohibitIsolatedConformances); if (subcastResult == DynamicCastResult::Failure) { for (unsigned k = 0; k != j; ++k) { const auto &elt = destTupleType->getElement(k); @@ -1310,7 +1315,7 @@ tryCastToFunction( OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *srcValue, const Metadata *srcType, const Metadata *&destFailureType, const Metadata *&srcFailureType, - bool takeOnSuccess, bool mayDeferChecks) + bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances) { assert(srcType != destType); assert(destType->getKind() == MetadataKind::Function); @@ -1372,7 +1377,8 @@ tryCastToFunction( static bool _conformsToProtocols(const OpaqueValue *value, const Metadata *type, const ExistentialTypeMetadata *existentialType, - const WitnessTable **conformances) { + const WitnessTable **conformances, + bool prohibitIsolatedConformances) { if (auto *superclass = existentialType->getSuperclassConstraint()) { if (!swift_dynamicCastMetatype(type, superclass)) return false; @@ -1385,7 +1391,7 @@ static bool _conformsToProtocols(const OpaqueValue *value, for (auto protocol : existentialType->getProtocols()) { if (!swift::_conformsToProtocolInContext( - value, type, protocol, conformances)) + value, type, protocol, conformances, prohibitIsolatedConformances)) return false; if (conformances != nullptr && protocol.needsWitnessTable()) { assert(*conformances != nullptr); @@ -1402,7 +1408,7 @@ tryCastToUnconstrainedOpaqueExistential( OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *srcValue, const Metadata *srcType, const Metadata *&destFailureType, const Metadata *&srcFailureType, - bool takeOnSuccess, bool mayDeferChecks) + bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances) { assert(srcType != destType); assert(destType->getKind() == MetadataKind::Existential); @@ -1429,7 +1435,7 @@ tryCastToConstrainedOpaqueExistential( OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *srcValue, const Metadata *srcType, const Metadata *&destFailureType, const Metadata *&srcFailureType, - bool takeOnSuccess, bool mayDeferChecks) + bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances) { assert(srcType != destType); assert(destType->getKind() == MetadataKind::Existential); @@ -1443,10 +1449,12 @@ tryCastToConstrainedOpaqueExistential( // TODO (rdar://17033499) If the source is an existential, we should // be able to compare the protocol constraints more efficiently than this. if (_conformsToProtocols(srcValue, srcType, destExistentialType, - destExistential->getWitnessTables())) { + destExistential->getWitnessTables(), + prohibitIsolatedConformances)) { return tryCastToUnconstrainedOpaqueExistential( destLocation, destType, srcValue, srcType, - destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks, + prohibitIsolatedConformances); } else { return DynamicCastResult::Failure; } @@ -1457,7 +1465,7 @@ tryCastToClassExistential( OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *srcValue, const Metadata *srcType, const Metadata *&destFailureType, const Metadata *&srcFailureType, - bool takeOnSuccess, bool mayDeferChecks) + bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances) { assert(srcType != destType); assert(destType->getKind() == MetadataKind::Existential); @@ -1480,7 +1488,8 @@ tryCastToClassExistential( auto value = reinterpret_cast(&tmp); auto type = reinterpret_cast(tmp); if (_conformsToProtocols(value, type, destExistentialType, - destExistentialLocation->getWitnessTables())) { + destExistentialLocation->getWitnessTables(), + prohibitIsolatedConformances)) { auto object = *(reinterpret_cast(value)); destExistentialLocation->Value = object; if (takeOnSuccess) { @@ -1529,7 +1538,8 @@ tryCastToClassExistential( } if (_conformsToProtocols(srcValue, srcType, destExistentialType, - destExistentialLocation->getWitnessTables())) { + destExistentialLocation->getWitnessTables(), + prohibitIsolatedConformances)) { destExistentialLocation->Value = srcObject; if (takeOnSuccess) { return DynamicCastResult::SuccessViaTake; @@ -1646,7 +1656,7 @@ tryCastToErrorExistential( OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *srcValue, const Metadata *srcType, const Metadata *&destFailureType, const Metadata *&srcFailureType, - bool takeOnSuccess, bool mayDeferChecks) + bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances) { assert(srcType != destType); assert(destType->getKind() == MetadataKind::Existential); @@ -1665,7 +1675,8 @@ tryCastToErrorExistential( assert(destExistentialType->NumProtocols == 1); const WitnessTable *errorWitness; if (_conformsToProtocols( - srcValue, srcType, destExistentialType, &errorWitness)) { + srcValue, srcType, destExistentialType, &errorWitness, + prohibitIsolatedConformances)) { #if SWIFT_OBJC_INTEROP // If it already holds an NSError, just use that. if (auto embedded = getErrorEmbeddedNSErrorIndirect( @@ -1697,7 +1708,7 @@ tryCastUnwrappingExistentialSource( OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *srcValue, const Metadata *srcType, const Metadata *&destFailureType, const Metadata *&srcFailureType, - bool takeOnSuccess, bool mayDeferChecks) + bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances) { assert(srcType != destType); assert(srcType->getKind() == MetadataKind::Existential); @@ -1738,13 +1749,14 @@ tryCastUnwrappingExistentialSource( srcInnerValue, srcInnerType, destFailureType, srcFailureType, takeOnSuccess && (srcInnerValue == srcValue), - mayDeferChecks); + mayDeferChecks, prohibitIsolatedConformances); } static DynamicCastResult tryCastUnwrappingExtendedExistentialSource( OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *srcValue, const Metadata *srcType, const Metadata *&destFailureType, - const Metadata *&srcFailureType, bool takeOnSuccess, bool mayDeferChecks) { + const Metadata *&srcFailureType, bool takeOnSuccess, bool mayDeferChecks, + bool prohibitIsolatedConformances) { assert(srcType != destType); assert(srcType->getKind() == MetadataKind::ExtendedExistential); @@ -1784,7 +1796,8 @@ static DynamicCastResult tryCastUnwrappingExtendedExistentialSource( srcFailureType = srcInnerType; return tryCast(destLocation, destType, srcInnerValue, srcInnerType, destFailureType, srcFailureType, - takeOnSuccess && (srcInnerValue == srcValue), mayDeferChecks); + takeOnSuccess && (srcInnerValue == srcValue), mayDeferChecks, + prohibitIsolatedConformances); } static DynamicCastResult @@ -1792,7 +1805,7 @@ tryCastUnwrappingExistentialMetatypeSource( OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *srcValue, const Metadata *srcType, const Metadata *&destFailureType, const Metadata *&srcFailureType, - bool takeOnSuccess, bool mayDeferChecks) + bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances) { assert(srcType != destType); assert(srcType->getKind() == MetadataKind::ExistentialMetatype); @@ -1807,14 +1820,15 @@ tryCastUnwrappingExistentialMetatypeSource( srcInnerValue, srcInnerType, destFailureType, srcFailureType, takeOnSuccess && (srcInnerValue == srcValue), - mayDeferChecks); + mayDeferChecks, prohibitIsolatedConformances); } static DynamicCastResult tryCastToExtendedExistential( OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *srcValue, const Metadata *srcType, const Metadata *&destFailureType, - const Metadata *&srcFailureType, bool takeOnSuccess, bool mayDeferChecks) { + const Metadata *&srcFailureType, bool takeOnSuccess, bool mayDeferChecks, + bool prohibitIsolatedConformances) { assert(srcType != destType); assert(destType->getKind() == MetadataKind::ExtendedExistential); @@ -1886,6 +1900,10 @@ static DynamicCastResult tryCastToExtendedExistential( if (error) return DynamicCastResult::Failure; + if (prohibitIsolatedConformances && + context.globalActorIsolationType) + return DynamicCastResult::Failure; + if (!swift_isInConformanceExecutionContext(selfType, &context)) return DynamicCastResult::Failure; } @@ -1951,7 +1969,7 @@ tryCastToOpaque( OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *srcValue, const Metadata *srcType, const Metadata *&destFailureType, const Metadata *&srcFailureType, - bool takeOnSuccess, bool mayDeferChecks) + bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances) { assert(srcType != destType); assert(destType->getKind() == MetadataKind::Opaque); @@ -1990,7 +2008,7 @@ tryCastToMetatype( OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *srcValue, const Metadata *srcType, const Metadata *&destFailureType, const Metadata *&srcFailureType, - bool takeOnSuccess, bool mayDeferChecks) + bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances) { assert(srcType != destType); assert(destType->getKind() == MetadataKind::Metatype); @@ -2023,7 +2041,8 @@ tryCastToMetatype( auto srcInnerValue = reinterpret_cast(&metatype); auto srcInnerType = swift_getMetatypeMetadata(metatype); return tryCast(destLocation, destType, srcInnerValue, srcInnerType, - destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks, + prohibitIsolatedConformances); } #endif return DynamicCastResult::Failure; @@ -2040,7 +2059,7 @@ _dynamicCastMetatypeToExistentialMetatype( OpaqueValue *destLocation, const ExistentialMetatypeMetadata *destType, const Metadata *srcMetatype, const Metadata *&destFailureType, const Metadata *&srcFailureType, - bool takeOnSuccess, bool mayDeferChecks) + bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances) { // The instance type of an existential metatype must be either an // existential or an existential metatype. @@ -2057,7 +2076,7 @@ _dynamicCastMetatypeToExistentialMetatype( = destMetatype ? destMetatype->getWitnessTables() : nullptr; if (!_conformsToProtocols(nullptr, srcMetatype, targetInstanceTypeAsExistential, - conformance)) { + conformance, prohibitIsolatedConformances)) { return DynamicCastResult::Failure; } @@ -2096,7 +2115,7 @@ _dynamicCastMetatypeToExistentialMetatype( srcInstanceType, destFailureType, srcFailureType, - takeOnSuccess, mayDeferChecks); + takeOnSuccess, mayDeferChecks, prohibitIsolatedConformances); } // "ExistentialMetatype" is the metatype for an existential type. @@ -2105,7 +2124,7 @@ tryCastToExistentialMetatype( OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *srcValue, const Metadata *srcType, const Metadata *&destFailureType, const Metadata *&srcFailureType, - bool takeOnSuccess, bool mayDeferChecks) + bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances) { assert(srcType != destType); assert(destType->getKind() == MetadataKind::ExistentialMetatype); @@ -2122,7 +2141,7 @@ tryCastToExistentialMetatype( srcMetatype, destFailureType, srcFailureType, - takeOnSuccess, mayDeferChecks); + takeOnSuccess, mayDeferChecks, prohibitIsolatedConformances); } case MetadataKind::ObjCClassWrapper: { @@ -2142,7 +2161,7 @@ tryCastToExistentialMetatype( metatype, destFailureType, srcFailureType, - takeOnSuccess, mayDeferChecks); + takeOnSuccess, mayDeferChecks, prohibitIsolatedConformances); } #endif return DynamicCastResult::Failure; @@ -2262,7 +2281,7 @@ tryCast( OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *srcValue, const Metadata *srcType, const Metadata *&destFailureType, const Metadata *&srcFailureType, - bool takeOnSuccess, bool mayDeferChecks) + bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances) { destFailureType = destType; srcFailureType = srcType; @@ -2295,7 +2314,8 @@ tryCast( return DynamicCastResult::Failure; } auto castResult = tryCastToDestType(destLocation, destType, srcValue, - srcType, destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + srcType, destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks, + prohibitIsolatedConformances); if (isSuccess(castResult)) { return castResult; } @@ -2312,7 +2332,8 @@ tryCast( srcFailureType = srcDynamicType; auto castResult = tryCastToDestType( destLocation, destType, srcValue, srcDynamicType, - destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks, + prohibitIsolatedConformances); if (isSuccess(castResult)) { return castResult; } @@ -2345,7 +2366,8 @@ tryCast( // Try unwrapping Obj-C __SwiftValue implementation auto subcastResult = tryCastUnwrappingObjCSwiftValueSource( destLocation, destType, srcValue, srcType, - destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks, + prohibitIsolatedConformances); if (isSuccess(subcastResult)) { return subcastResult; } @@ -2379,7 +2401,8 @@ tryCast( case MetadataKind::Existential: { auto subcastResult = tryCastUnwrappingExistentialSource( destLocation, destType, srcValue, srcType, - destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks, + prohibitIsolatedConformances); if (isSuccess(subcastResult)) { return subcastResult; } @@ -2389,7 +2412,8 @@ tryCast( case MetadataKind::ExistentialMetatype: { auto subcastResult = tryCastUnwrappingExistentialMetatypeSource( destLocation, destType, srcValue, srcType, - destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks, + prohibitIsolatedConformances); if (isSuccess(subcastResult)) { return subcastResult; } @@ -2399,7 +2423,8 @@ tryCast( case MetadataKind::ExtendedExistential: { auto subcastResult = tryCastUnwrappingExtendedExistentialSource( destLocation, destType, srcValue, srcType, destFailureType, - srcFailureType, takeOnSuccess, mayDeferChecks); + srcFailureType, takeOnSuccess, mayDeferChecks, + prohibitIsolatedConformances); if (isSuccess(subcastResult)) { return subcastResult; } @@ -2423,14 +2448,16 @@ tryCast( if (srcKind == MetadataKind::Optional) { auto subcastResult = tryCastUnwrappingOptionalBoth( destLocation, destType, srcValue, srcType, - destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks, + prohibitIsolatedConformances); if (isSuccess(subcastResult)) { return subcastResult; } } auto subcastResult = tryCastUnwrappingOptionalDestination( destLocation, destType, srcValue, srcType, - destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks, + prohibitIsolatedConformances); if (isSuccess(subcastResult)) { return subcastResult; } @@ -2439,7 +2466,8 @@ tryCast( if (srcKind == MetadataKind::Optional) { auto subcastResult = tryCastUnwrappingOptionalSource( destLocation, destType, srcValue, srcType, - destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); + destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks, + prohibitIsolatedConformances); if (isSuccess(subcastResult)) { return subcastResult; } @@ -2583,6 +2611,11 @@ swift_dynamicCastImpl(OpaqueValue *destLocation, // actually accessed. bool mayDeferChecks = flags & DynamicCastFlags::Unconditional; + // Whether the compiler told us that we aren't allowed to use *any* isolated + // conformances, regardless of whether we are in that isolation domain. + bool prohibitIsolatedConformances = + flags & DynamicCastFlags::ProhibitIsolatedConformances; + // Attempt the cast... const Metadata *destFailureType = destType; const Metadata *srcFailureType = srcType; @@ -2590,7 +2623,7 @@ swift_dynamicCastImpl(OpaqueValue *destLocation, destLocation, destType, srcValue, srcType, destFailureType, srcFailureType, - takeOnSuccess, mayDeferChecks); + takeOnSuccess, mayDeferChecks, prohibitIsolatedConformances); switch (result) { case DynamicCastResult::Failure: diff --git a/stdlib/public/runtime/Private.h b/stdlib/public/runtime/Private.h index 2ef15f450a2..58f4783e9b2 100644 --- a/stdlib/public/runtime/Private.h +++ b/stdlib/public/runtime/Private.h @@ -721,7 +721,8 @@ public: const OpaqueValue *value, const Metadata *type, ProtocolDescriptorRef protocol, - const WitnessTable **conformance); + const WitnessTable **conformance, + bool prohibitIsolatedConformances); /// Construct type metadata for the given protocol. const Metadata * diff --git a/test/Concurrency/Runtime/isolated_conformance.swift b/test/Concurrency/Runtime/isolated_conformance.swift index ecda8b34b3b..ca3a3534404 100644 --- a/test/Concurrency/Runtime/isolated_conformance.swift +++ b/test/Concurrency/Runtime/isolated_conformance.swift @@ -20,6 +20,10 @@ protocol Q { func g() } +protocol R: Sendable { + func h() +} + nonisolated class MyClass: @MainActor P { func f() { print("MyClass.f()") @@ -45,6 +49,12 @@ extension MyClass: @SomeGlobalActor Q { } } +extension MyClass: nonisolated R { + nonisolated func h() { + print("MyClass.h()") + } +} + struct Wrapper { var wrapped: T } @@ -63,6 +73,13 @@ extension Wrapper: Q where T: Q { } } +extension Wrapper: R where T: R { + func h() { + print("Wrapper for ", terminator: "") + wrapped.h() + } +} + @available(SwiftStdlib 5.9, *) struct WrapMany { var wrapped: (repeat each T) @@ -82,14 +99,23 @@ extension WrapMany: Q where repeat each T: Q { } } -extension Int: P, Q { - func f() { } - func g() { } +@available(SwiftStdlib 5.9, *) +extension WrapMany: R where repeat each T: R { + func h() { + print("Wrapper for many") + } } -extension String: P, Q { +extension Int: P, Q, R { func f() { } func g() { } + func h() { } +} + +extension String: P, Q, R { + func f() { } + func g() { } + func h() { } } func tryCastToP(_ value: any Sendable) -> Bool { @@ -102,6 +128,16 @@ func tryCastToP(_ value: any Sendable) -> Bool { return false } +func tryCastToPAndR(_ value: any Sendable) -> Bool { + if let p = value as? any P & R { + p.f() + return true + } + + print("Conformance did not match") + return false +} + func tryCastToQ(_ value: any Sendable) -> Bool { if let q = value as? any Q { q.g() @@ -134,6 +170,11 @@ await Task.detached { @MainActor in precondition(tryCastToP(mc)) precondition(tryCastToP(wrappedMC)) + // Cannot cast to P & R because the conformance to P is isolated, but R + // is Sendable. + precondition(!tryCastToPAndR(mc)) + precondition(!tryCastToPAndR(wrappedMC)) + if #available(SwiftStdlib 5.9, *) { let wrappedMany = WrapMany(wrapped: (17, mc, "Pack")) precondition(tryCastToP(wrappedMany)) @@ -149,6 +190,11 @@ await Task.detached { @SomeGlobalActor in precondition(tryCastToQ(mc)) precondition(tryCastToQ(wrappedMC)) + // Cannot cast to P & R because the conformance to P is isolated, but R + // is Sendable. + precondition(!tryCastToPAndR(mc)) + precondition(!tryCastToPAndR(wrappedMC)) + if #available(SwiftStdlib 5.9, *) { let wrappedMany = WrapMany(wrapped: (17, mc, "Pack")) precondition(tryCastToQ(wrappedMany)) @@ -176,5 +222,6 @@ await Task.detached { } }.value + // Ensure that we access mc later print(mc)