[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;
/// 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;

View File

@@ -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);

View File

@@ -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(

View File

@@ -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);

View File

@@ -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<const ExistentialTypeMetadata *>(targetType);
if (_conformsToProtocols(nullptr, sourceType, targetTypeAsExistential, nullptr))
if (_conformsToProtocols(nullptr, sourceType, targetTypeAsExistential,
nullptr, /*prohibitIsolatedConformances=*/false))
return origSourceType;
swift_dynamicCastFailure(sourceType, targetType);
}

View File

@@ -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<OpaqueValue *>(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<OpaqueValue *>(&tmp);
auto type = reinterpret_cast<const Metadata *>(tmp);
if (_conformsToProtocols(value, type, destExistentialType,
destExistentialLocation->getWitnessTables())) {
destExistentialLocation->getWitnessTables(),
prohibitIsolatedConformances)) {
auto object = *(reinterpret_cast<HeapObject **>(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<OpaqueValue *>(&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:

View File

@@ -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 *

View File

@@ -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<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, *)
struct WrapMany<each T> {
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)