[SE-0470] Prohibit isolated conformances in dynamic casts marked as such

Certain dynamic casts cannot work safely with isolated conformances,
regardless of what executor the code runs on. For such cases, reject
all attempts to conform to the type.
This commit is contained in:
Doug Gregor
2025-03-26 22:29:12 -07:00
parent e0b52cd20e
commit 43df05a89c
8 changed files with 202 additions and 84 deletions

View File

@@ -313,6 +313,11 @@ enum class DynamicCastFlags : size_t {
/// True if the cast should destroy the source value on failure; /// True if the cast should destroy the source value on failure;
/// false if the value should be left in place. /// false if the value should be left in place.
DestroyOnFailure = 0x4, 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) { inline bool operator&(DynamicCastFlags a, DynamicCastFlags b) {
return (size_t(a) & size_t(b)) != 0; return (size_t(a) & size_t(b)) != 0;

View File

@@ -42,8 +42,11 @@ using namespace swift;
using namespace irgen; using namespace irgen;
/// Compute the flags to pass to swift_dynamicCast. /// Compute the flags to pass to swift_dynamicCast.
static DynamicCastFlags getDynamicCastFlags(CastConsumptionKind consumptionKind, static DynamicCastFlags getDynamicCastFlags(
CheckedCastMode mode) { CastConsumptionKind consumptionKind,
CheckedCastMode mode,
CastingIsolatedConformances isolatedConformances
) {
DynamicCastFlags flags = DynamicCastFlags::Default; DynamicCastFlags flags = DynamicCastFlags::Default;
if (mode == CheckedCastMode::Unconditional) if (mode == CheckedCastMode::Unconditional)
@@ -53,6 +56,14 @@ static DynamicCastFlags getDynamicCastFlags(CastConsumptionKind consumptionKind,
if (shouldTakeOnSuccess(consumptionKind)) if (shouldTakeOnSuccess(consumptionKind))
flags |= DynamicCastFlags::TakeOnSuccess; flags |= DynamicCastFlags::TakeOnSuccess;
switch (isolatedConformances) {
case CastingIsolatedConformances::Allow:
break;
case CastingIsolatedConformances::Prohibit:
flags |= DynamicCastFlags::ProhibitIsolatedConformances;
break;
}
return flags; return flags;
} }
@@ -63,10 +74,12 @@ llvm::Value *irgen::emitCheckedCast(IRGenFunction &IGF,
Address dest, Address dest,
CanType targetType, CanType targetType,
CastConsumptionKind consumptionKind, CastConsumptionKind consumptionKind,
CheckedCastMode mode) { CheckedCastMode mode,
CastingIsolatedConformances isolatedConformances) {
// TODO: attempt to specialize this based on the known types. // 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. // Cast both addresses to opaque pointer type.
dest = IGF.Builder.CreateElementBitCast(dest, IGF.IGM.OpaqueTy); dest = IGF.Builder.CreateElementBitCast(dest, IGF.IGM.OpaqueTy);
@@ -847,6 +860,7 @@ void irgen::emitScalarCheckedCast(IRGenFunction &IGF,
SILType targetLoweredType, SILType targetLoweredType,
CanType targetFormalType, CanType targetFormalType,
CheckedCastMode mode, CheckedCastMode mode,
CastingIsolatedConformances isolatedConformances,
Explosion &out) { Explosion &out) {
assert(sourceLoweredType.isObject()); assert(sourceLoweredType.isObject());
assert(targetLoweredType.isObject()); assert(targetLoweredType.isObject());
@@ -976,7 +990,7 @@ void irgen::emitScalarCheckedCast(IRGenFunction &IGF,
src, sourceFormalType, src, sourceFormalType,
dest, targetFormalType, dest, targetFormalType,
CastConsumptionKind::TakeAlways, CastConsumptionKind::TakeAlways,
mode); mode, isolatedConformances);
llvm::Value *successResult = IGF.Builder.CreateLoad(dest); llvm::Value *successResult = IGF.Builder.CreateLoad(dest);
llvm::Value *failureResult = llvm::ConstantPointerNull::get(destPtrType); llvm::Value *failureResult = llvm::ConstantPointerNull::get(destPtrType);
llvm::Value *result = IGF.Builder.CreateSelect(success, successResult, failureResult); llvm::Value *result = IGF.Builder.CreateSelect(success, successResult, failureResult);

View File

@@ -28,6 +28,7 @@ namespace swift {
class SILType; class SILType;
class ProtocolDecl; class ProtocolDecl;
enum class CastConsumptionKind : unsigned char; enum class CastConsumptionKind : unsigned char;
enum class CastingIsolatedConformances: uint8_t;
namespace irgen { namespace irgen {
class Address; class Address;
@@ -46,7 +47,8 @@ namespace irgen {
Address dest, Address dest,
CanType toType, CanType toType,
CastConsumptionKind consumptionKind, CastConsumptionKind consumptionKind,
CheckedCastMode mode); CheckedCastMode mode,
CastingIsolatedConformances isolatedConformances);
void emitScalarCheckedCast(IRGenFunction &IGF, Explosion &value, void emitScalarCheckedCast(IRGenFunction &IGF, Explosion &value,
SILType sourceLoweredType, SILType sourceLoweredType,
@@ -54,6 +56,7 @@ namespace irgen {
SILType targetLoweredType, SILType targetLoweredType,
CanType targetFormalType, CanType targetFormalType,
CheckedCastMode mode, CheckedCastMode mode,
CastingIsolatedConformances isolatedConformances,
Explosion &out); Explosion &out);
llvm::Value *emitFastClassCastIfPossible( llvm::Value *emitFastClassCastIfPossible(

View File

@@ -7186,7 +7186,8 @@ visitUncheckedRefCastAddrInst(swift::UncheckedRefCastAddrInst *i) {
src, i->getSourceFormalType(), src, i->getSourceFormalType(),
dest, i->getTargetFormalType(), dest, i->getTargetFormalType(),
CastConsumptionKind::TakeAlways, CastConsumptionKind::TakeAlways,
CheckedCastMode::Unconditional); CheckedCastMode::Unconditional,
CastingIsolatedConformances::Allow);
} }
void IRGenSILFunction::visitUncheckedAddrCastInst( void IRGenSILFunction::visitUncheckedAddrCastInst(
@@ -7416,6 +7417,7 @@ void IRGenSILFunction::visitUnconditionalCheckedCastInst(
i->getTargetLoweredType(), i->getTargetLoweredType(),
i->getTargetFormalType(), i->getTargetFormalType(),
CheckedCastMode::Unconditional, CheckedCastMode::Unconditional,
i->getIsolatedConformances(),
ex); ex);
setLoweredExplosion(i, ex); setLoweredExplosion(i, ex);
} }
@@ -7604,7 +7606,8 @@ void IRGenSILFunction::visitUnconditionalCheckedCastAddrInst(
src, i->getSourceFormalType(), src, i->getSourceFormalType(),
dest, i->getTargetFormalType(), dest, i->getTargetFormalType(),
CastConsumptionKind::TakeAlways, CastConsumptionKind::TakeAlways,
CheckedCastMode::Unconditional); CheckedCastMode::Unconditional,
i->getIsolatedConformances());
} }
void IRGenSILFunction::visitCheckedCastBranchInst( void IRGenSILFunction::visitCheckedCastBranchInst(
@@ -7625,6 +7628,7 @@ void IRGenSILFunction::visitCheckedCastBranchInst(
i->getTargetLoweredType(), i->getTargetLoweredType(),
i->getTargetFormalType(), i->getTargetFormalType(),
CheckedCastMode::Conditional, CheckedCastMode::Conditional,
i->getIsolatedConformances(),
ex); ex);
auto val = ex.claimNext(); auto val = ex.claimNext();
castResult.casted = val; castResult.casted = val;
@@ -7662,7 +7666,8 @@ void IRGenSILFunction::visitCheckedCastAddrBranchInst(
emitCheckedCast(*this, emitCheckedCast(*this,
src, i->getSourceFormalType(), src, i->getSourceFormalType(),
dest, i->getTargetFormalType(), dest, i->getTargetFormalType(),
i->getConsumptionKind(), CheckedCastMode::Conditional); i->getConsumptionKind(), CheckedCastMode::Conditional,
i->getIsolatedConformances());
Builder.CreateCondBr(castSucceeded, Builder.CreateCondBr(castSucceeded,
getLoweredBB(i->getSuccessBB()).bb, getLoweredBB(i->getSuccessBB()).bb,
getLoweredBB(i->getFailureBB()).bb); getLoweredBB(i->getFailureBB()).bb);

View File

@@ -614,12 +614,19 @@ bool swift::_conformsToProtocolInContext(
const OpaqueValue *value, const OpaqueValue *value,
const Metadata *type, const Metadata *type,
ProtocolDescriptorRef protocol, ProtocolDescriptorRef protocol,
const WitnessTable **conformance) { const WitnessTable **conformance,
bool prohibitIsolatedConformances) {
ConformanceExecutionContext context; ConformanceExecutionContext context;
if (!_conformsToProtocol(value, type, protocol, conformance, &context)) if (!_conformsToProtocol(value, type, protocol, conformance, &context))
return false; 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)) if (!swift_isInConformanceExecutionContext(type, &context))
return false; return false;
@@ -631,7 +638,8 @@ bool swift::_conformsToProtocolInContext(
static bool _conformsToProtocols(const OpaqueValue *value, static bool _conformsToProtocols(const OpaqueValue *value,
const Metadata *type, const Metadata *type,
const ExistentialTypeMetadata *existentialType, const ExistentialTypeMetadata *existentialType,
const WitnessTable **conformances) { const WitnessTable **conformances,
bool prohibitIsolatedConformances) {
if (auto *superclass = existentialType->getSuperclassConstraint()) { if (auto *superclass = existentialType->getSuperclassConstraint()) {
if (!swift_dynamicCastMetatype(type, superclass)) if (!swift_dynamicCastMetatype(type, superclass))
return false; return false;
@@ -644,7 +652,7 @@ static bool _conformsToProtocols(const OpaqueValue *value,
for (auto protocol : existentialType->getProtocols()) { for (auto protocol : existentialType->getProtocols()) {
if (!_conformsToProtocolInContext( if (!_conformsToProtocolInContext(
value, type, protocol, conformances)) value, type, protocol, conformances, prohibitIsolatedConformances))
return false; return false;
if (conformances != nullptr && protocol.needsWitnessTable()) { if (conformances != nullptr && protocol.needsWitnessTable()) {
assert(*conformances != nullptr); assert(*conformances != nullptr);
@@ -1050,9 +1058,10 @@ swift_dynamicCastMetatypeImpl(const Metadata *sourceType,
} }
static const Metadata * static const Metadata *
swift_dynamicCastMetatypeUnconditionalImpl(const Metadata *sourceType, swift_dynamicCastMetatypeUnconditionalImpl(
const Metadata *targetType, const Metadata *sourceType,
const char *file, unsigned line, unsigned column) { const Metadata *targetType,
const char *file, unsigned line, unsigned column) {
auto origSourceType = sourceType; auto origSourceType = sourceType;
// Identical types always succeed // Identical types always succeed
@@ -1138,7 +1147,8 @@ swift_dynamicCastMetatypeUnconditionalImpl(const Metadata *sourceType,
case MetadataKind::Existential: { case MetadataKind::Existential: {
auto targetTypeAsExistential = static_cast<const ExistentialTypeMetadata *>(targetType); auto targetTypeAsExistential = static_cast<const ExistentialTypeMetadata *>(targetType);
if (_conformsToProtocols(nullptr, sourceType, targetTypeAsExistential, nullptr)) if (_conformsToProtocols(nullptr, sourceType, targetTypeAsExistential,
nullptr, /*prohibitIsolatedConformances=*/false))
return origSourceType; return origSourceType;
swift_dynamicCastFailure(sourceType, targetType); swift_dynamicCastFailure(sourceType, targetType);
} }

View File

@@ -87,7 +87,7 @@ typedef DynamicCastResult (tryCastFunctionType)(
OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *destLocation, const Metadata *destType,
OpaqueValue *srcValue, const Metadata *srcType, OpaqueValue *srcValue, const Metadata *srcType,
const Metadata *&destFailureType, const Metadata *&srcFailureType, const Metadata *&destFailureType, const Metadata *&srcFailureType,
bool takeOnSuccess, bool mayDeferChecks bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances
); );
// Forward-declare the main top-level `tryCast()` function // Forward-declare the main top-level `tryCast()` function
@@ -401,7 +401,7 @@ tryCastUnwrappingObjCSwiftValueSource(
OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *destLocation, const Metadata *destType,
OpaqueValue *srcValue, const Metadata *srcType, OpaqueValue *srcValue, const Metadata *srcType,
const Metadata *&destFailureType, const Metadata *&srcFailureType, const Metadata *&destFailureType, const Metadata *&srcFailureType,
bool takeOnSuccess, bool mayDeferChecks) bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances)
{ {
id srcObject; id srcObject;
memcpy(&srcObject, srcValue, sizeof(id)); memcpy(&srcObject, srcValue, sizeof(id));
@@ -422,7 +422,7 @@ tryCastUnwrappingObjCSwiftValueSource(
destLocation, destType, destLocation, destType,
const_cast<OpaqueValue *>(srcInnerValue), srcInnerType, const_cast<OpaqueValue *>(srcInnerValue), srcInnerType,
destFailureType, srcFailureType, destFailureType, srcFailureType,
/*takeOnSuccess=*/ false, mayDeferChecks); /*takeOnSuccess=*/ false, mayDeferChecks, prohibitIsolatedConformances);
} }
#else #else
static DynamicCastResult static DynamicCastResult
@@ -430,7 +430,7 @@ tryCastUnwrappingSwiftValueSource(
OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *destLocation, const Metadata *destType,
OpaqueValue *srcValue, const Metadata *srcType, OpaqueValue *srcValue, const Metadata *srcType,
const Metadata *&destFailureType, const Metadata *&srcFailureType, const Metadata *&destFailureType, const Metadata *&srcFailureType,
bool takeOnSuccess, bool mayDeferChecks) bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances)
{ {
assert(srcType->getKind() == MetadataKind::Class); assert(srcType->getKind() == MetadataKind::Class);
@@ -452,7 +452,7 @@ tryCastToSwiftClass(
OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *destLocation, const Metadata *destType,
OpaqueValue *srcValue, const Metadata *srcType, OpaqueValue *srcValue, const Metadata *srcType,
const Metadata *&destFailureType, const Metadata *&srcFailureType, const Metadata *&destFailureType, const Metadata *&srcFailureType,
bool takeOnSuccess, bool mayDeferChecks) bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances)
{ {
assert(srcType != destType); assert(srcType != destType);
assert(destType->getKind() == MetadataKind::Class); assert(destType->getKind() == MetadataKind::Class);
@@ -496,7 +496,7 @@ tryCastToObjectiveCClass(
OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *destLocation, const Metadata *destType,
OpaqueValue *srcValue, const Metadata *srcType, OpaqueValue *srcValue, const Metadata *srcType,
const Metadata *&destFailureType, const Metadata *&srcFailureType, const Metadata *&destFailureType, const Metadata *&srcFailureType,
bool takeOnSuccess, bool mayDeferChecks) bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances)
{ {
assert(srcType != destType); assert(srcType != destType);
assert(destType->getKind() == MetadataKind::ObjCClassWrapper); assert(destType->getKind() == MetadataKind::ObjCClassWrapper);
@@ -546,7 +546,7 @@ tryCastToForeignClass(
OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *destLocation, const Metadata *destType,
OpaqueValue *srcValue, const Metadata *srcType, OpaqueValue *srcValue, const Metadata *srcType,
const Metadata *&destFailureType, const Metadata *&srcFailureType, const Metadata *&destFailureType, const Metadata *&srcFailureType,
bool takeOnSuccess, bool mayDeferChecks) bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances)
{ {
#if SWIFT_OBJC_INTEROP #if SWIFT_OBJC_INTEROP
assert(srcType != destType); assert(srcType != destType);
@@ -594,7 +594,8 @@ tryCastToForeignClass(
static DynamicCastResult tryCastToForeignReferenceType( static DynamicCastResult tryCastToForeignReferenceType(
OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *srcValue, OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *srcValue,
const Metadata *srcType, const Metadata *&destFailureType, 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 != destType);
assert(destType->getKind() == MetadataKind::ForeignReferenceType); assert(destType->getKind() == MetadataKind::ForeignReferenceType);
@@ -610,7 +611,7 @@ tryCastToEnum(
OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *destLocation, const Metadata *destType,
OpaqueValue *srcValue, const Metadata *srcType, OpaqueValue *srcValue, const Metadata *srcType,
const Metadata *&destFailureType, const Metadata *&srcFailureType, const Metadata *&destFailureType, const Metadata *&srcFailureType,
bool takeOnSuccess, bool mayDeferChecks) bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances)
{ {
assert(srcType != destType); assert(srcType != destType);
// Note: Optional is handled elsewhere // Note: Optional is handled elsewhere
@@ -783,7 +784,7 @@ tryCastToAnyHashable(
OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *destLocation, const Metadata *destType,
OpaqueValue *srcValue, const Metadata *srcType, OpaqueValue *srcValue, const Metadata *srcType,
const Metadata *&destFailureType, const Metadata *&srcFailureType, const Metadata *&destFailureType, const Metadata *&srcFailureType,
bool takeOnSuccess, bool mayDeferChecks) bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances)
{ {
assert(srcType != destType); assert(srcType != destType);
assert(destType->getKind() == MetadataKind::Struct); assert(destType->getKind() == MetadataKind::Struct);
@@ -859,7 +860,7 @@ tryCastToArray(
OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *destLocation, const Metadata *destType,
OpaqueValue *srcValue, const Metadata *srcType, OpaqueValue *srcValue, const Metadata *srcType,
const Metadata *&destFailureType, const Metadata *&srcFailureType, const Metadata *&destFailureType, const Metadata *&srcFailureType,
bool takeOnSuccess, bool mayDeferChecks) bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances)
{ {
assert(srcType != destType); assert(srcType != destType);
assert(destType->getKind() == MetadataKind::Struct); assert(destType->getKind() == MetadataKind::Struct);
@@ -899,7 +900,7 @@ tryCastToDictionary(
OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *destLocation, const Metadata *destType,
OpaqueValue *srcValue, const Metadata *srcType, OpaqueValue *srcValue, const Metadata *srcType,
const Metadata *&destFailureType, const Metadata *&srcFailureType, const Metadata *&destFailureType, const Metadata *&srcFailureType,
bool takeOnSuccess, bool mayDeferChecks) bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances)
{ {
assert(srcType != destType); assert(srcType != destType);
assert(destType->getKind() == MetadataKind::Struct); assert(destType->getKind() == MetadataKind::Struct);
@@ -940,7 +941,7 @@ tryCastToSet(
OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *destLocation, const Metadata *destType,
OpaqueValue *srcValue, const Metadata *srcType, OpaqueValue *srcValue, const Metadata *srcType,
const Metadata *&destFailureType, const Metadata *&srcFailureType, const Metadata *&destFailureType, const Metadata *&srcFailureType,
bool takeOnSuccess, bool mayDeferChecks) bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances)
{ {
assert(srcType != destType); assert(srcType != destType);
assert(destType->getKind() == MetadataKind::Struct); assert(destType->getKind() == MetadataKind::Struct);
@@ -982,7 +983,7 @@ tryCastToString(
OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *destLocation, const Metadata *destType,
OpaqueValue *srcValue, const Metadata *srcType, OpaqueValue *srcValue, const Metadata *srcType,
const Metadata *&destFailureType, const Metadata *&srcFailureType, const Metadata *&destFailureType, const Metadata *&srcFailureType,
bool takeOnSuccess, bool mayDeferChecks) bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances)
{ {
assert(srcType != destType); assert(srcType != destType);
assert(destType->getKind() == MetadataKind::Struct); assert(destType->getKind() == MetadataKind::Struct);
@@ -1013,7 +1014,7 @@ tryCastToStruct(
OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *destLocation, const Metadata *destType,
OpaqueValue *srcValue, const Metadata *srcType, OpaqueValue *srcValue, const Metadata *srcType,
const Metadata *&destFailureType, const Metadata *&srcFailureType, const Metadata *&destFailureType, const Metadata *&srcFailureType,
bool takeOnSuccess, bool mayDeferChecks) bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances)
{ {
assert(srcType != destType); assert(srcType != destType);
assert(destType->getKind() == MetadataKind::Struct); assert(destType->getKind() == MetadataKind::Struct);
@@ -1036,7 +1037,7 @@ tryCastToOptional(
OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *destLocation, const Metadata *destType,
OpaqueValue *srcValue, const Metadata *srcType, OpaqueValue *srcValue, const Metadata *srcType,
const Metadata *&destFailureType, const Metadata *&srcFailureType, const Metadata *&destFailureType, const Metadata *&srcFailureType,
bool takeOnSuccess, bool mayDeferChecks) bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances)
{ {
assert(srcType != destType); assert(srcType != destType);
assert(destType->getKind() == MetadataKind::Optional); assert(destType->getKind() == MetadataKind::Optional);
@@ -1110,7 +1111,7 @@ tryCastUnwrappingOptionalBoth(
OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *destLocation, const Metadata *destType,
OpaqueValue *srcValue, const Metadata *srcType, OpaqueValue *srcValue, const Metadata *srcType,
const Metadata *&destFailureType, const Metadata *&srcFailureType, const Metadata *&destFailureType, const Metadata *&srcFailureType,
bool takeOnSuccess, bool mayDeferChecks) bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances)
{ {
assert(destType->getKind() == MetadataKind::Optional); assert(destType->getKind() == MetadataKind::Optional);
assert(srcType->getKind() == MetadataKind::Optional); assert(srcType->getKind() == MetadataKind::Optional);
@@ -1134,7 +1135,8 @@ tryCastUnwrappingOptionalBoth(
auto destInnerLocation = destLocation; // Single-payload enum layout auto destInnerLocation = destLocation; // Single-payload enum layout
auto subcastResult = tryCast( auto subcastResult = tryCast(
destInnerLocation, destInnerType, srcValue, srcInnerType, destInnerLocation, destInnerType, srcValue, srcInnerType,
destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks,
prohibitIsolatedConformances);
if (isSuccess(subcastResult)) { if (isSuccess(subcastResult)) {
destInnerType->vw_storeEnumTagSinglePayload( destInnerType->vw_storeEnumTagSinglePayload(
destLocation, /*case*/ 0, /*emptyCases*/ 1); destLocation, /*case*/ 0, /*emptyCases*/ 1);
@@ -1153,7 +1155,7 @@ tryCastUnwrappingOptionalDestination(
OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *destLocation, const Metadata *destType,
OpaqueValue *srcValue, const Metadata *srcType, OpaqueValue *srcValue, const Metadata *srcType,
const Metadata *&destFailureType, const Metadata *&srcFailureType, const Metadata *&destFailureType, const Metadata *&srcFailureType,
bool takeOnSuccess, bool mayDeferChecks) bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances)
{ {
assert(destType->getKind() == MetadataKind::Optional); assert(destType->getKind() == MetadataKind::Optional);
@@ -1162,7 +1164,8 @@ tryCastUnwrappingOptionalDestination(
auto destInnerLocation = destLocation; // Single-payload enum layout auto destInnerLocation = destLocation; // Single-payload enum layout
auto subcastResult = tryCast( auto subcastResult = tryCast(
destInnerLocation, destInnerType, srcValue, srcType, destInnerLocation, destInnerType, srcValue, srcType,
destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks,
prohibitIsolatedConformances);
if (isSuccess(subcastResult)) { if (isSuccess(subcastResult)) {
destInnerType->vw_storeEnumTagSinglePayload( destInnerType->vw_storeEnumTagSinglePayload(
destLocation, /*case*/ 0, /*emptyCases*/ 1); destLocation, /*case*/ 0, /*emptyCases*/ 1);
@@ -1179,7 +1182,7 @@ tryCastUnwrappingOptionalSource(
OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *destLocation, const Metadata *destType,
OpaqueValue *srcValue, const Metadata *srcType, OpaqueValue *srcValue, const Metadata *srcType,
const Metadata *&destFailureType, const Metadata *&srcFailureType, const Metadata *&destFailureType, const Metadata *&srcFailureType,
bool takeOnSuccess, bool mayDeferChecks) bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances)
{ {
assert(srcType->getKind() == MetadataKind::Optional); assert(srcType->getKind() == MetadataKind::Optional);
@@ -1190,7 +1193,8 @@ tryCastUnwrappingOptionalSource(
if (nonNil) { if (nonNil) {
// Recurse with unwrapped source // Recurse with unwrapped source
return tryCast(destLocation, destType, srcValue, srcInnerType, return tryCast(destLocation, destType, srcValue, srcInnerType,
destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks,
prohibitIsolatedConformances);
} }
return DynamicCastResult::Failure; return DynamicCastResult::Failure;
} }
@@ -1208,7 +1212,7 @@ tryCastToTuple(
OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *destLocation, const Metadata *destType,
OpaqueValue *srcValue, const Metadata *srcType, OpaqueValue *srcValue, const Metadata *srcType,
const Metadata *&destFailureType, const Metadata *&srcFailureType, const Metadata *&destFailureType, const Metadata *&srcFailureType,
bool takeOnSuccess, bool mayDeferChecks) bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances)
{ {
assert(srcType != destType); assert(srcType != destType);
assert(destType->getKind() == MetadataKind::Tuple); assert(destType->getKind() == MetadataKind::Tuple);
@@ -1284,7 +1288,8 @@ tryCastToTuple(
auto subcastResult = tryCast(destElt.findIn(destLocation), destElt.Type, auto subcastResult = tryCast(destElt.findIn(destLocation), destElt.Type,
srcElt.findIn(srcValue), srcElt.Type, srcElt.findIn(srcValue), srcElt.Type,
destFailureType, srcFailureType, destFailureType, srcFailureType,
false, mayDeferChecks); false, mayDeferChecks,
prohibitIsolatedConformances);
if (subcastResult == DynamicCastResult::Failure) { if (subcastResult == DynamicCastResult::Failure) {
for (unsigned k = 0; k != j; ++k) { for (unsigned k = 0; k != j; ++k) {
const auto &elt = destTupleType->getElement(k); const auto &elt = destTupleType->getElement(k);
@@ -1310,7 +1315,7 @@ tryCastToFunction(
OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *destLocation, const Metadata *destType,
OpaqueValue *srcValue, const Metadata *srcType, OpaqueValue *srcValue, const Metadata *srcType,
const Metadata *&destFailureType, const Metadata *&srcFailureType, const Metadata *&destFailureType, const Metadata *&srcFailureType,
bool takeOnSuccess, bool mayDeferChecks) bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances)
{ {
assert(srcType != destType); assert(srcType != destType);
assert(destType->getKind() == MetadataKind::Function); assert(destType->getKind() == MetadataKind::Function);
@@ -1372,7 +1377,8 @@ tryCastToFunction(
static bool _conformsToProtocols(const OpaqueValue *value, static bool _conformsToProtocols(const OpaqueValue *value,
const Metadata *type, const Metadata *type,
const ExistentialTypeMetadata *existentialType, const ExistentialTypeMetadata *existentialType,
const WitnessTable **conformances) { const WitnessTable **conformances,
bool prohibitIsolatedConformances) {
if (auto *superclass = existentialType->getSuperclassConstraint()) { if (auto *superclass = existentialType->getSuperclassConstraint()) {
if (!swift_dynamicCastMetatype(type, superclass)) if (!swift_dynamicCastMetatype(type, superclass))
return false; return false;
@@ -1385,7 +1391,7 @@ static bool _conformsToProtocols(const OpaqueValue *value,
for (auto protocol : existentialType->getProtocols()) { for (auto protocol : existentialType->getProtocols()) {
if (!swift::_conformsToProtocolInContext( if (!swift::_conformsToProtocolInContext(
value, type, protocol, conformances)) value, type, protocol, conformances, prohibitIsolatedConformances))
return false; return false;
if (conformances != nullptr && protocol.needsWitnessTable()) { if (conformances != nullptr && protocol.needsWitnessTable()) {
assert(*conformances != nullptr); assert(*conformances != nullptr);
@@ -1402,7 +1408,7 @@ tryCastToUnconstrainedOpaqueExistential(
OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *destLocation, const Metadata *destType,
OpaqueValue *srcValue, const Metadata *srcType, OpaqueValue *srcValue, const Metadata *srcType,
const Metadata *&destFailureType, const Metadata *&srcFailureType, const Metadata *&destFailureType, const Metadata *&srcFailureType,
bool takeOnSuccess, bool mayDeferChecks) bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances)
{ {
assert(srcType != destType); assert(srcType != destType);
assert(destType->getKind() == MetadataKind::Existential); assert(destType->getKind() == MetadataKind::Existential);
@@ -1429,7 +1435,7 @@ tryCastToConstrainedOpaqueExistential(
OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *destLocation, const Metadata *destType,
OpaqueValue *srcValue, const Metadata *srcType, OpaqueValue *srcValue, const Metadata *srcType,
const Metadata *&destFailureType, const Metadata *&srcFailureType, const Metadata *&destFailureType, const Metadata *&srcFailureType,
bool takeOnSuccess, bool mayDeferChecks) bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances)
{ {
assert(srcType != destType); assert(srcType != destType);
assert(destType->getKind() == MetadataKind::Existential); assert(destType->getKind() == MetadataKind::Existential);
@@ -1443,10 +1449,12 @@ tryCastToConstrainedOpaqueExistential(
// TODO (rdar://17033499) If the source is an existential, we should // TODO (rdar://17033499) If the source is an existential, we should
// be able to compare the protocol constraints more efficiently than this. // be able to compare the protocol constraints more efficiently than this.
if (_conformsToProtocols(srcValue, srcType, destExistentialType, if (_conformsToProtocols(srcValue, srcType, destExistentialType,
destExistential->getWitnessTables())) { destExistential->getWitnessTables(),
prohibitIsolatedConformances)) {
return tryCastToUnconstrainedOpaqueExistential( return tryCastToUnconstrainedOpaqueExistential(
destLocation, destType, srcValue, srcType, destLocation, destType, srcValue, srcType,
destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks,
prohibitIsolatedConformances);
} else { } else {
return DynamicCastResult::Failure; return DynamicCastResult::Failure;
} }
@@ -1457,7 +1465,7 @@ tryCastToClassExistential(
OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *destLocation, const Metadata *destType,
OpaqueValue *srcValue, const Metadata *srcType, OpaqueValue *srcValue, const Metadata *srcType,
const Metadata *&destFailureType, const Metadata *&srcFailureType, const Metadata *&destFailureType, const Metadata *&srcFailureType,
bool takeOnSuccess, bool mayDeferChecks) bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances)
{ {
assert(srcType != destType); assert(srcType != destType);
assert(destType->getKind() == MetadataKind::Existential); assert(destType->getKind() == MetadataKind::Existential);
@@ -1480,7 +1488,8 @@ tryCastToClassExistential(
auto value = reinterpret_cast<OpaqueValue *>(&tmp); auto value = reinterpret_cast<OpaqueValue *>(&tmp);
auto type = reinterpret_cast<const Metadata *>(tmp); auto type = reinterpret_cast<const Metadata *>(tmp);
if (_conformsToProtocols(value, type, destExistentialType, if (_conformsToProtocols(value, type, destExistentialType,
destExistentialLocation->getWitnessTables())) { destExistentialLocation->getWitnessTables(),
prohibitIsolatedConformances)) {
auto object = *(reinterpret_cast<HeapObject **>(value)); auto object = *(reinterpret_cast<HeapObject **>(value));
destExistentialLocation->Value = object; destExistentialLocation->Value = object;
if (takeOnSuccess) { if (takeOnSuccess) {
@@ -1529,7 +1538,8 @@ tryCastToClassExistential(
} }
if (_conformsToProtocols(srcValue, srcType, if (_conformsToProtocols(srcValue, srcType,
destExistentialType, destExistentialType,
destExistentialLocation->getWitnessTables())) { destExistentialLocation->getWitnessTables(),
prohibitIsolatedConformances)) {
destExistentialLocation->Value = srcObject; destExistentialLocation->Value = srcObject;
if (takeOnSuccess) { if (takeOnSuccess) {
return DynamicCastResult::SuccessViaTake; return DynamicCastResult::SuccessViaTake;
@@ -1646,7 +1656,7 @@ tryCastToErrorExistential(
OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *destLocation, const Metadata *destType,
OpaqueValue *srcValue, const Metadata *srcType, OpaqueValue *srcValue, const Metadata *srcType,
const Metadata *&destFailureType, const Metadata *&srcFailureType, const Metadata *&destFailureType, const Metadata *&srcFailureType,
bool takeOnSuccess, bool mayDeferChecks) bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances)
{ {
assert(srcType != destType); assert(srcType != destType);
assert(destType->getKind() == MetadataKind::Existential); assert(destType->getKind() == MetadataKind::Existential);
@@ -1665,7 +1675,8 @@ tryCastToErrorExistential(
assert(destExistentialType->NumProtocols == 1); assert(destExistentialType->NumProtocols == 1);
const WitnessTable *errorWitness; const WitnessTable *errorWitness;
if (_conformsToProtocols( if (_conformsToProtocols(
srcValue, srcType, destExistentialType, &errorWitness)) { srcValue, srcType, destExistentialType, &errorWitness,
prohibitIsolatedConformances)) {
#if SWIFT_OBJC_INTEROP #if SWIFT_OBJC_INTEROP
// If it already holds an NSError, just use that. // If it already holds an NSError, just use that.
if (auto embedded = getErrorEmbeddedNSErrorIndirect( if (auto embedded = getErrorEmbeddedNSErrorIndirect(
@@ -1697,7 +1708,7 @@ tryCastUnwrappingExistentialSource(
OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *destLocation, const Metadata *destType,
OpaqueValue *srcValue, const Metadata *srcType, OpaqueValue *srcValue, const Metadata *srcType,
const Metadata *&destFailureType, const Metadata *&srcFailureType, const Metadata *&destFailureType, const Metadata *&srcFailureType,
bool takeOnSuccess, bool mayDeferChecks) bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances)
{ {
assert(srcType != destType); assert(srcType != destType);
assert(srcType->getKind() == MetadataKind::Existential); assert(srcType->getKind() == MetadataKind::Existential);
@@ -1738,13 +1749,14 @@ tryCastUnwrappingExistentialSource(
srcInnerValue, srcInnerType, srcInnerValue, srcInnerType,
destFailureType, srcFailureType, destFailureType, srcFailureType,
takeOnSuccess && (srcInnerValue == srcValue), takeOnSuccess && (srcInnerValue == srcValue),
mayDeferChecks); mayDeferChecks, prohibitIsolatedConformances);
} }
static DynamicCastResult tryCastUnwrappingExtendedExistentialSource( static DynamicCastResult tryCastUnwrappingExtendedExistentialSource(
OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *srcValue, OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *srcValue,
const Metadata *srcType, const Metadata *&destFailureType, 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 != destType);
assert(srcType->getKind() == MetadataKind::ExtendedExistential); assert(srcType->getKind() == MetadataKind::ExtendedExistential);
@@ -1784,7 +1796,8 @@ static DynamicCastResult tryCastUnwrappingExtendedExistentialSource(
srcFailureType = srcInnerType; srcFailureType = srcInnerType;
return tryCast(destLocation, destType, srcInnerValue, srcInnerType, return tryCast(destLocation, destType, srcInnerValue, srcInnerType,
destFailureType, srcFailureType, destFailureType, srcFailureType,
takeOnSuccess && (srcInnerValue == srcValue), mayDeferChecks); takeOnSuccess && (srcInnerValue == srcValue), mayDeferChecks,
prohibitIsolatedConformances);
} }
static DynamicCastResult static DynamicCastResult
@@ -1792,7 +1805,7 @@ tryCastUnwrappingExistentialMetatypeSource(
OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *destLocation, const Metadata *destType,
OpaqueValue *srcValue, const Metadata *srcType, OpaqueValue *srcValue, const Metadata *srcType,
const Metadata *&destFailureType, const Metadata *&srcFailureType, const Metadata *&destFailureType, const Metadata *&srcFailureType,
bool takeOnSuccess, bool mayDeferChecks) bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances)
{ {
assert(srcType != destType); assert(srcType != destType);
assert(srcType->getKind() == MetadataKind::ExistentialMetatype); assert(srcType->getKind() == MetadataKind::ExistentialMetatype);
@@ -1807,14 +1820,15 @@ tryCastUnwrappingExistentialMetatypeSource(
srcInnerValue, srcInnerType, srcInnerValue, srcInnerType,
destFailureType, srcFailureType, destFailureType, srcFailureType,
takeOnSuccess && (srcInnerValue == srcValue), takeOnSuccess && (srcInnerValue == srcValue),
mayDeferChecks); mayDeferChecks, prohibitIsolatedConformances);
} }
static DynamicCastResult tryCastToExtendedExistential( static DynamicCastResult tryCastToExtendedExistential(
OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *srcValue, OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *srcValue,
const Metadata *srcType, const Metadata *&destFailureType, 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 != destType);
assert(destType->getKind() == MetadataKind::ExtendedExistential); assert(destType->getKind() == MetadataKind::ExtendedExistential);
@@ -1886,6 +1900,10 @@ static DynamicCastResult tryCastToExtendedExistential(
if (error) if (error)
return DynamicCastResult::Failure; return DynamicCastResult::Failure;
if (prohibitIsolatedConformances &&
context.globalActorIsolationType)
return DynamicCastResult::Failure;
if (!swift_isInConformanceExecutionContext(selfType, &context)) if (!swift_isInConformanceExecutionContext(selfType, &context))
return DynamicCastResult::Failure; return DynamicCastResult::Failure;
} }
@@ -1951,7 +1969,7 @@ tryCastToOpaque(
OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *destLocation, const Metadata *destType,
OpaqueValue *srcValue, const Metadata *srcType, OpaqueValue *srcValue, const Metadata *srcType,
const Metadata *&destFailureType, const Metadata *&srcFailureType, const Metadata *&destFailureType, const Metadata *&srcFailureType,
bool takeOnSuccess, bool mayDeferChecks) bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances)
{ {
assert(srcType != destType); assert(srcType != destType);
assert(destType->getKind() == MetadataKind::Opaque); assert(destType->getKind() == MetadataKind::Opaque);
@@ -1990,7 +2008,7 @@ tryCastToMetatype(
OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *destLocation, const Metadata *destType,
OpaqueValue *srcValue, const Metadata *srcType, OpaqueValue *srcValue, const Metadata *srcType,
const Metadata *&destFailureType, const Metadata *&srcFailureType, const Metadata *&destFailureType, const Metadata *&srcFailureType,
bool takeOnSuccess, bool mayDeferChecks) bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances)
{ {
assert(srcType != destType); assert(srcType != destType);
assert(destType->getKind() == MetadataKind::Metatype); assert(destType->getKind() == MetadataKind::Metatype);
@@ -2023,7 +2041,8 @@ tryCastToMetatype(
auto srcInnerValue = reinterpret_cast<OpaqueValue *>(&metatype); auto srcInnerValue = reinterpret_cast<OpaqueValue *>(&metatype);
auto srcInnerType = swift_getMetatypeMetadata(metatype); auto srcInnerType = swift_getMetatypeMetadata(metatype);
return tryCast(destLocation, destType, srcInnerValue, srcInnerType, return tryCast(destLocation, destType, srcInnerValue, srcInnerType,
destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks,
prohibitIsolatedConformances);
} }
#endif #endif
return DynamicCastResult::Failure; return DynamicCastResult::Failure;
@@ -2040,7 +2059,7 @@ _dynamicCastMetatypeToExistentialMetatype(
OpaqueValue *destLocation, const ExistentialMetatypeMetadata *destType, OpaqueValue *destLocation, const ExistentialMetatypeMetadata *destType,
const Metadata *srcMetatype, const Metadata *srcMetatype,
const Metadata *&destFailureType, const Metadata *&srcFailureType, 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 // The instance type of an existential metatype must be either an
// existential or an existential metatype. // existential or an existential metatype.
@@ -2057,7 +2076,7 @@ _dynamicCastMetatypeToExistentialMetatype(
= destMetatype ? destMetatype->getWitnessTables() : nullptr; = destMetatype ? destMetatype->getWitnessTables() : nullptr;
if (!_conformsToProtocols(nullptr, srcMetatype, if (!_conformsToProtocols(nullptr, srcMetatype,
targetInstanceTypeAsExistential, targetInstanceTypeAsExistential,
conformance)) { conformance, prohibitIsolatedConformances)) {
return DynamicCastResult::Failure; return DynamicCastResult::Failure;
} }
@@ -2096,7 +2115,7 @@ _dynamicCastMetatypeToExistentialMetatype(
srcInstanceType, srcInstanceType,
destFailureType, destFailureType,
srcFailureType, srcFailureType,
takeOnSuccess, mayDeferChecks); takeOnSuccess, mayDeferChecks, prohibitIsolatedConformances);
} }
// "ExistentialMetatype" is the metatype for an existential type. // "ExistentialMetatype" is the metatype for an existential type.
@@ -2105,7 +2124,7 @@ tryCastToExistentialMetatype(
OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *destLocation, const Metadata *destType,
OpaqueValue *srcValue, const Metadata *srcType, OpaqueValue *srcValue, const Metadata *srcType,
const Metadata *&destFailureType, const Metadata *&srcFailureType, const Metadata *&destFailureType, const Metadata *&srcFailureType,
bool takeOnSuccess, bool mayDeferChecks) bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances)
{ {
assert(srcType != destType); assert(srcType != destType);
assert(destType->getKind() == MetadataKind::ExistentialMetatype); assert(destType->getKind() == MetadataKind::ExistentialMetatype);
@@ -2122,7 +2141,7 @@ tryCastToExistentialMetatype(
srcMetatype, srcMetatype,
destFailureType, destFailureType,
srcFailureType, srcFailureType,
takeOnSuccess, mayDeferChecks); takeOnSuccess, mayDeferChecks, prohibitIsolatedConformances);
} }
case MetadataKind::ObjCClassWrapper: { case MetadataKind::ObjCClassWrapper: {
@@ -2142,7 +2161,7 @@ tryCastToExistentialMetatype(
metatype, metatype,
destFailureType, destFailureType,
srcFailureType, srcFailureType,
takeOnSuccess, mayDeferChecks); takeOnSuccess, mayDeferChecks, prohibitIsolatedConformances);
} }
#endif #endif
return DynamicCastResult::Failure; return DynamicCastResult::Failure;
@@ -2262,7 +2281,7 @@ tryCast(
OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *destLocation, const Metadata *destType,
OpaqueValue *srcValue, const Metadata *srcType, OpaqueValue *srcValue, const Metadata *srcType,
const Metadata *&destFailureType, const Metadata *&srcFailureType, const Metadata *&destFailureType, const Metadata *&srcFailureType,
bool takeOnSuccess, bool mayDeferChecks) bool takeOnSuccess, bool mayDeferChecks, bool prohibitIsolatedConformances)
{ {
destFailureType = destType; destFailureType = destType;
srcFailureType = srcType; srcFailureType = srcType;
@@ -2295,7 +2314,8 @@ tryCast(
return DynamicCastResult::Failure; return DynamicCastResult::Failure;
} }
auto castResult = tryCastToDestType(destLocation, destType, srcValue, auto castResult = tryCastToDestType(destLocation, destType, srcValue,
srcType, destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); srcType, destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks,
prohibitIsolatedConformances);
if (isSuccess(castResult)) { if (isSuccess(castResult)) {
return castResult; return castResult;
} }
@@ -2312,7 +2332,8 @@ tryCast(
srcFailureType = srcDynamicType; srcFailureType = srcDynamicType;
auto castResult = tryCastToDestType( auto castResult = tryCastToDestType(
destLocation, destType, srcValue, srcDynamicType, destLocation, destType, srcValue, srcDynamicType,
destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks,
prohibitIsolatedConformances);
if (isSuccess(castResult)) { if (isSuccess(castResult)) {
return castResult; return castResult;
} }
@@ -2345,7 +2366,8 @@ tryCast(
// Try unwrapping Obj-C __SwiftValue implementation // Try unwrapping Obj-C __SwiftValue implementation
auto subcastResult = tryCastUnwrappingObjCSwiftValueSource( auto subcastResult = tryCastUnwrappingObjCSwiftValueSource(
destLocation, destType, srcValue, srcType, destLocation, destType, srcValue, srcType,
destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks,
prohibitIsolatedConformances);
if (isSuccess(subcastResult)) { if (isSuccess(subcastResult)) {
return subcastResult; return subcastResult;
} }
@@ -2379,7 +2401,8 @@ tryCast(
case MetadataKind::Existential: { case MetadataKind::Existential: {
auto subcastResult = tryCastUnwrappingExistentialSource( auto subcastResult = tryCastUnwrappingExistentialSource(
destLocation, destType, srcValue, srcType, destLocation, destType, srcValue, srcType,
destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks,
prohibitIsolatedConformances);
if (isSuccess(subcastResult)) { if (isSuccess(subcastResult)) {
return subcastResult; return subcastResult;
} }
@@ -2389,7 +2412,8 @@ tryCast(
case MetadataKind::ExistentialMetatype: { case MetadataKind::ExistentialMetatype: {
auto subcastResult = tryCastUnwrappingExistentialMetatypeSource( auto subcastResult = tryCastUnwrappingExistentialMetatypeSource(
destLocation, destType, srcValue, srcType, destLocation, destType, srcValue, srcType,
destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks,
prohibitIsolatedConformances);
if (isSuccess(subcastResult)) { if (isSuccess(subcastResult)) {
return subcastResult; return subcastResult;
} }
@@ -2399,7 +2423,8 @@ tryCast(
case MetadataKind::ExtendedExistential: { case MetadataKind::ExtendedExistential: {
auto subcastResult = tryCastUnwrappingExtendedExistentialSource( auto subcastResult = tryCastUnwrappingExtendedExistentialSource(
destLocation, destType, srcValue, srcType, destFailureType, destLocation, destType, srcValue, srcType, destFailureType,
srcFailureType, takeOnSuccess, mayDeferChecks); srcFailureType, takeOnSuccess, mayDeferChecks,
prohibitIsolatedConformances);
if (isSuccess(subcastResult)) { if (isSuccess(subcastResult)) {
return subcastResult; return subcastResult;
} }
@@ -2423,14 +2448,16 @@ tryCast(
if (srcKind == MetadataKind::Optional) { if (srcKind == MetadataKind::Optional) {
auto subcastResult = tryCastUnwrappingOptionalBoth( auto subcastResult = tryCastUnwrappingOptionalBoth(
destLocation, destType, srcValue, srcType, destLocation, destType, srcValue, srcType,
destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks,
prohibitIsolatedConformances);
if (isSuccess(subcastResult)) { if (isSuccess(subcastResult)) {
return subcastResult; return subcastResult;
} }
} }
auto subcastResult = tryCastUnwrappingOptionalDestination( auto subcastResult = tryCastUnwrappingOptionalDestination(
destLocation, destType, srcValue, srcType, destLocation, destType, srcValue, srcType,
destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks,
prohibitIsolatedConformances);
if (isSuccess(subcastResult)) { if (isSuccess(subcastResult)) {
return subcastResult; return subcastResult;
} }
@@ -2439,7 +2466,8 @@ tryCast(
if (srcKind == MetadataKind::Optional) { if (srcKind == MetadataKind::Optional) {
auto subcastResult = tryCastUnwrappingOptionalSource( auto subcastResult = tryCastUnwrappingOptionalSource(
destLocation, destType, srcValue, srcType, destLocation, destType, srcValue, srcType,
destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks); destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks,
prohibitIsolatedConformances);
if (isSuccess(subcastResult)) { if (isSuccess(subcastResult)) {
return subcastResult; return subcastResult;
} }
@@ -2583,6 +2611,11 @@ swift_dynamicCastImpl(OpaqueValue *destLocation,
// actually accessed. // actually accessed.
bool mayDeferChecks = flags & DynamicCastFlags::Unconditional; 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... // Attempt the cast...
const Metadata *destFailureType = destType; const Metadata *destFailureType = destType;
const Metadata *srcFailureType = srcType; const Metadata *srcFailureType = srcType;
@@ -2590,7 +2623,7 @@ swift_dynamicCastImpl(OpaqueValue *destLocation,
destLocation, destType, destLocation, destType,
srcValue, srcType, srcValue, srcType,
destFailureType, srcFailureType, destFailureType, srcFailureType,
takeOnSuccess, mayDeferChecks); takeOnSuccess, mayDeferChecks, prohibitIsolatedConformances);
switch (result) { switch (result) {
case DynamicCastResult::Failure: case DynamicCastResult::Failure:

View File

@@ -721,7 +721,8 @@ public:
const OpaqueValue *value, const OpaqueValue *value,
const Metadata *type, const Metadata *type,
ProtocolDescriptorRef protocol, ProtocolDescriptorRef protocol,
const WitnessTable **conformance); const WitnessTable **conformance,
bool prohibitIsolatedConformances);
/// Construct type metadata for the given protocol. /// Construct type metadata for the given protocol.
const Metadata * const Metadata *

View File

@@ -20,6 +20,10 @@ protocol Q {
func g() func g()
} }
protocol R: Sendable {
func h()
}
nonisolated class MyClass: @MainActor P { nonisolated class MyClass: @MainActor P {
func f() { func f() {
print("MyClass.f()") print("MyClass.f()")
@@ -45,6 +49,12 @@ extension MyClass: @SomeGlobalActor Q {
} }
} }
extension MyClass: nonisolated R {
nonisolated func h() {
print("MyClass.h()")
}
}
struct Wrapper<T> { struct Wrapper<T> {
var wrapped: T 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, *) @available(SwiftStdlib 5.9, *)
struct WrapMany<each T> { struct WrapMany<each T> {
var wrapped: (repeat each T) var wrapped: (repeat each T)
@@ -82,14 +99,23 @@ extension WrapMany: Q where repeat each T: Q {
} }
} }
extension Int: P, Q { @available(SwiftStdlib 5.9, *)
func f() { } extension WrapMany: R where repeat each T: R {
func g() { } func h() {
print("Wrapper for many")
}
} }
extension String: P, Q { extension Int: P, Q, R {
func f() { } func f() { }
func g() { } func g() { }
func h() { }
}
extension String: P, Q, R {
func f() { }
func g() { }
func h() { }
} }
func tryCastToP(_ value: any Sendable) -> Bool { func tryCastToP(_ value: any Sendable) -> Bool {
@@ -102,6 +128,16 @@ func tryCastToP(_ value: any Sendable) -> Bool {
return false 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 { func tryCastToQ(_ value: any Sendable) -> Bool {
if let q = value as? any Q { if let q = value as? any Q {
q.g() q.g()
@@ -134,6 +170,11 @@ await Task.detached { @MainActor in
precondition(tryCastToP(mc)) precondition(tryCastToP(mc))
precondition(tryCastToP(wrappedMC)) 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, *) { if #available(SwiftStdlib 5.9, *) {
let wrappedMany = WrapMany(wrapped: (17, mc, "Pack")) let wrappedMany = WrapMany(wrapped: (17, mc, "Pack"))
precondition(tryCastToP(wrappedMany)) precondition(tryCastToP(wrappedMany))
@@ -149,6 +190,11 @@ await Task.detached { @SomeGlobalActor in
precondition(tryCastToQ(mc)) precondition(tryCastToQ(mc))
precondition(tryCastToQ(wrappedMC)) 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, *) { if #available(SwiftStdlib 5.9, *) {
let wrappedMany = WrapMany(wrapped: (17, mc, "Pack")) let wrappedMany = WrapMany(wrapped: (17, mc, "Pack"))
precondition(tryCastToQ(wrappedMany)) precondition(tryCastToQ(wrappedMany))
@@ -176,5 +222,6 @@ await Task.detached {
} }
}.value }.value
// Ensure that we access mc later // Ensure that we access mc later
print(mc) print(mc)