-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[5.7] Runtime Casting for Extended Existentials #59511
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
99fb23c
603558f
8e7733d
e063528
9a7f821
ce2dfeb
c35e122
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1695,10 +1695,56 @@ tryCastUnwrappingExistentialSource( | |
return tryCast(destLocation, destType, | ||
srcInnerValue, srcInnerType, | ||
destFailureType, srcFailureType, | ||
takeOnSuccess & (srcInnerValue == srcValue), | ||
takeOnSuccess && (srcInnerValue == srcValue), | ||
mayDeferChecks); | ||
} | ||
|
||
static DynamicCastResult tryCastUnwrappingExtendedExistentialSource( | ||
OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *srcValue, | ||
const Metadata *srcType, const Metadata *&destFailureType, | ||
const Metadata *&srcFailureType, bool takeOnSuccess, bool mayDeferChecks) { | ||
assert(srcType != destType); | ||
assert(srcType->getKind() == MetadataKind::ExtendedExistential); | ||
|
||
auto srcExistentialType = cast<ExtendedExistentialTypeMetadata>(srcType); | ||
|
||
// Unpack the existential content | ||
const Metadata *srcInnerType = nullptr; | ||
OpaqueValue *srcInnerValue = nullptr; | ||
switch (srcExistentialType->Shape->Flags.getSpecialKind()) { | ||
case ExtendedExistentialTypeShape::SpecialKind::None: { | ||
auto opaqueContainer = | ||
reinterpret_cast<OpaqueExistentialContainer *>(srcValue); | ||
srcInnerType = opaqueContainer->Type; | ||
srcInnerValue = const_cast<OpaqueValue *>(opaqueContainer->projectValue()); | ||
break; | ||
} | ||
case ExtendedExistentialTypeShape::SpecialKind::Class: { | ||
auto classContainer = | ||
reinterpret_cast<ClassExistentialContainer *>(srcValue); | ||
srcInnerType = swift_getObjectType((HeapObject *)classContainer->Value); | ||
srcInnerValue = reinterpret_cast<OpaqueValue *>(&classContainer->Value); | ||
break; | ||
} | ||
case ExtendedExistentialTypeShape::SpecialKind::Metatype: { | ||
auto srcExistentialContainer = | ||
reinterpret_cast<ExistentialMetatypeContainer *>(srcValue); | ||
srcInnerType = swift_getMetatypeMetadata(srcExistentialContainer->Value); | ||
srcInnerValue = reinterpret_cast<OpaqueValue *>(&srcExistentialContainer->Value); | ||
break; | ||
} | ||
case ExtendedExistentialTypeShape::SpecialKind::ExplicitLayout: { | ||
swift_unreachable("Explicit layout not yet implemented"); | ||
break; | ||
} | ||
} | ||
|
||
srcFailureType = srcInnerType; | ||
return tryCast(destLocation, destType, srcInnerValue, srcInnerType, | ||
destFailureType, srcFailureType, | ||
takeOnSuccess & (srcInnerValue == srcValue), mayDeferChecks); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It should be! @rjmccall caught this the first time around. I'll patch this out on main. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
} | ||
|
||
static DynamicCastResult | ||
tryCastUnwrappingExistentialMetatypeSource( | ||
OpaqueValue *destLocation, const Metadata *destType, | ||
|
@@ -1722,6 +1768,134 @@ tryCastUnwrappingExistentialMetatypeSource( | |
mayDeferChecks); | ||
} | ||
|
||
|
||
static DynamicCastResult tryCastToExtendedExistential( | ||
OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *srcValue, | ||
const Metadata *srcType, const Metadata *&destFailureType, | ||
const Metadata *&srcFailureType, bool takeOnSuccess, bool mayDeferChecks) { | ||
assert(srcType != destType); | ||
assert(destType->getKind() == MetadataKind::ExtendedExistential); | ||
|
||
auto destExistentialType = cast<ExtendedExistentialTypeMetadata>(destType); | ||
auto *destExistentialShape = destExistentialType->Shape; | ||
const unsigned shapeArgumentCount = | ||
destExistentialShape->getGenSigArgumentLayoutSizeInWords(); | ||
const Metadata *selfType = srcType; | ||
|
||
// If we have a type expression to look into, unwrap as much metatype | ||
// structure as possible so we can reach the type metadata for the 'Self' | ||
// parameter. | ||
if (destExistentialShape->Flags.hasTypeExpression()) { | ||
Demangler dem; | ||
auto *node = dem.demangleType(destExistentialShape->getTypeExpression()->name.get()); | ||
if (!node) | ||
return DynamicCastResult::Failure; | ||
|
||
while (node->getKind() == Demangle::Node::Kind::Type && | ||
node->getNumChildren() && | ||
node->getChild(0)->getKind() == Demangle::Node::Kind::Metatype && | ||
node->getChild(0)->getNumChildren()) { | ||
auto *metatypeMetadata = dyn_cast<MetatypeMetadata>(selfType); | ||
if (!metatypeMetadata) | ||
return DynamicCastResult::Failure; | ||
|
||
selfType = metatypeMetadata->InstanceType; | ||
node = node->getChild(0)->getChild(0); | ||
} | ||
|
||
// Make sure the thing we've pulled out at the end is a dependent | ||
// generic parameter. | ||
if (!(node->getKind() == Demangle::Node::Kind::Type && | ||
node->getNumChildren() && | ||
node->getChild(0)->getKind() == | ||
Demangle::Node::Kind::DependentGenericParamType)) | ||
return DynamicCastResult::Failure; | ||
} | ||
|
||
llvm::SmallVector<const void *, 8> allGenericArgsVec; | ||
unsigned witnessesMark = 0; | ||
{ | ||
// Line up the arguments to the requirement signature. | ||
auto genArgs = destExistentialType->getGeneralizationArguments(); | ||
allGenericArgsVec.append(genArgs, genArgs + shapeArgumentCount); | ||
// Tack on the `Self` argument. | ||
allGenericArgsVec.push_back((const void *)selfType); | ||
// Mark the point where the generic arguments end. | ||
// _checkGenericRequirements is going to fill in a set of witness tables | ||
// after that. | ||
witnessesMark = allGenericArgsVec.size(); | ||
|
||
SubstGenericParametersFromMetadata substitutions(destExistentialShape, | ||
allGenericArgsVec.data()); | ||
// Verify the requirements in the requirement signature against the | ||
// arguments from the source value. | ||
auto error = swift::_checkGenericRequirements( | ||
destExistentialShape->getRequirementSignature().getRequirements(), | ||
allGenericArgsVec, | ||
[&substitutions](unsigned depth, unsigned index) { | ||
return substitutions.getMetadata(depth, index); | ||
}, | ||
[](const Metadata *type, unsigned index) -> const WitnessTable * { | ||
swift_unreachable("Resolution of witness tables is not supported"); | ||
}); | ||
if (error) | ||
return DynamicCastResult::Failure; | ||
} | ||
|
||
OpaqueValue *destBox = nullptr; | ||
const WitnessTable **destWitnesses = nullptr; | ||
switch (destExistentialShape->Flags.getSpecialKind()) { | ||
case ExtendedExistentialTypeShape::SpecialKind::None: { | ||
auto destExistential = | ||
reinterpret_cast<OpaqueExistentialContainer *>(destLocation); | ||
|
||
// Allocate a box and fill in the type information. | ||
destExistential->Type = srcType; | ||
destBox = srcType->allocateBoxForExistentialIn(&destExistential->Buffer); | ||
destWitnesses = destExistential->getWitnessTables(); | ||
break; | ||
} | ||
case ExtendedExistentialTypeShape::SpecialKind::Class: { | ||
auto destExistential = | ||
reinterpret_cast<ClassExistentialContainer *>(destLocation); | ||
destBox = reinterpret_cast<OpaqueValue *>(&destExistential->Value); | ||
destWitnesses = destExistential->getWitnessTables(); | ||
break; | ||
} | ||
case ExtendedExistentialTypeShape::SpecialKind::Metatype: { | ||
auto destExistential = | ||
reinterpret_cast<ExistentialMetatypeContainer *>(destLocation); | ||
destBox = reinterpret_cast<OpaqueValue *>(&destExistential->Value); | ||
destWitnesses = destExistential->getWitnessTables(); | ||
break; | ||
} | ||
case ExtendedExistentialTypeShape::SpecialKind::ExplicitLayout: | ||
swift_unreachable("Witnesses for explicit layout not yet implemented"); | ||
} | ||
|
||
// Fill in the trailing set of witness tables. | ||
const unsigned numWitnessTables = allGenericArgsVec.size() - witnessesMark; | ||
assert(numWitnessTables == | ||
llvm::count_if(destExistentialShape->getRequirementSignature().getRequirements(), | ||
[](const auto &req) -> bool { | ||
return req.getKind() == | ||
GenericRequirementKind::Protocol; | ||
})); | ||
for (unsigned i = 0; i < numWitnessTables; ++i) { | ||
const auto witness = i + witnessesMark; | ||
destWitnesses[i] = | ||
reinterpret_cast<const WitnessTable *>(allGenericArgsVec[witness]); | ||
} | ||
|
||
if (takeOnSuccess) { | ||
srcType->vw_initializeWithTake(destBox, srcValue); | ||
return DynamicCastResult::SuccessViaTake; | ||
} else { | ||
srcType->vw_initializeWithCopy(destBox, srcValue); | ||
return DynamicCastResult::SuccessViaCopy; | ||
} | ||
} | ||
|
||
/******************************************************************************/ | ||
/**************************** Opaque Destination ******************************/ | ||
/******************************************************************************/ | ||
|
@@ -2006,12 +2180,14 @@ static tryCastFunctionType *selectCasterForDest(const Metadata *destType) { | |
swift_unreachable( | ||
"Unknown existential type representation in dynamic cast dispatch"); | ||
} | ||
case MetadataKind::ExtendedExistential: | ||
return tryCastToExtendedExistential; | ||
case MetadataKind::Metatype: | ||
return tryCastToMetatype; | ||
case MetadataKind::ObjCClassWrapper: | ||
return tryCastToMetatype; | ||
case MetadataKind::ObjCClassWrapper: | ||
return tryCastToObjectiveCClass; | ||
case MetadataKind::ExistentialMetatype: | ||
return tryCastToExistentialMetatype; | ||
return tryCastToExistentialMetatype; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thank you for fixing whitespace. |
||
case MetadataKind::HeapLocalVariable: | ||
case MetadataKind::HeapGenericLocalVariable: | ||
case MetadataKind::ErrorObject: | ||
|
@@ -2169,6 +2345,15 @@ tryCast( | |
break; | ||
} | ||
|
||
case MetadataKind::ExtendedExistential: { | ||
auto subcastResult = tryCastUnwrappingExtendedExistentialSource( | ||
destLocation, destType, srcValue, srcType, destFailureType, | ||
srcFailureType, takeOnSuccess, mayDeferChecks); | ||
if (isSuccess(subcastResult)) { | ||
return subcastResult; | ||
} | ||
break; | ||
} | ||
default: | ||
break; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice catch!