Skip to content

Commit 9e4670a

Browse files
committed
Implement Casting For Extended Existentials
Implement casting to and from extended existentials. This is done by slightly generalizing the conditional conformances checking infrastructure. Unfortunately, casts for reference types and metatypes are unsound because IRGen is peepholing all non-opaque existential conversions with a helper. I’ll disable that in a follow-up. rdar://92197049
1 parent 14edd57 commit 9e4670a

File tree

7 files changed

+334
-155
lines changed

7 files changed

+334
-155
lines changed

include/swift/ABI/Metadata.h

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2125,16 +2125,6 @@ struct TargetExtendedExistentialTypeMetadata
21252125
return this->template getTrailingObjects<ConstTargetPointer<Runtime, void>>();
21262126
}
21272127

2128-
public:
2129-
/// Project the value pointer from an extended existential container of the
2130-
/// type described by this metadata.
2131-
const OpaqueValue *projectValue(const OpaqueValue *container) const;
2132-
2133-
OpaqueValue *projectValue(OpaqueValue *container) const {
2134-
return const_cast<OpaqueValue *>(
2135-
projectValue((const OpaqueValue *)container));
2136-
}
2137-
21382128
public:
21392129
static bool classof(const TargetMetadata<Runtime> *metadata) {
21402130
return metadata->getKind() == MetadataKind::ExtendedExistential;

stdlib/public/runtime/Demangle.cpp

Lines changed: 43 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -316,48 +316,6 @@ _buildDemanglingForNominalType(const Metadata *type, Demangle::Demangler &Dem) {
316316
return _buildDemanglingForContext(description, demangledGenerics, Dem);
317317
}
318318

319-
static Demangle::NodePointer
320-
_buildDemanglingForProtocolDescriptor(ProtocolDescriptorRef protocol,
321-
Demangle::Demangler &Dem) {
322-
#if SWIFT_OBJC_INTEROP
323-
if (protocol.isObjC()) {
324-
// The protocol name is mangled as a type symbol, with the _Tt prefix.
325-
StringRef ProtoName(protocol.getName());
326-
NodePointer protocolNode = Dem.demangleSymbol(ProtoName);
327-
328-
// ObjC protocol names aren't mangled.
329-
if (!protocolNode) {
330-
auto module = Dem.createNode(Node::Kind::Module, MANGLING_MODULE_OBJC);
331-
auto node = Dem.createNode(Node::Kind::Protocol);
332-
node->addChild(module, Dem);
333-
node->addChild(Dem.createNode(Node::Kind::Identifier, ProtoName), Dem);
334-
auto typeNode = Dem.createNode(Node::Kind::Type);
335-
typeNode->addChild(node, Dem);
336-
return typeNode;
337-
}
338-
339-
// Dig out the protocol node.
340-
// Global -> (Protocol|TypeMangling)
341-
protocolNode = protocolNode->getChild(0);
342-
if (protocolNode->getKind() == Node::Kind::TypeMangling) {
343-
protocolNode = protocolNode->getChild(0); // TypeMangling -> Type
344-
protocolNode = protocolNode->getChild(0); // Type -> ProtocolList
345-
protocolNode = protocolNode->getChild(0); // ProtocolList -> TypeList
346-
protocolNode = protocolNode->getChild(0); // TypeList -> Type
347-
348-
assert(protocolNode->getKind() == Node::Kind::Type);
349-
assert(protocolNode->getChild(0)->getKind() == Node::Kind::Protocol);
350-
} else {
351-
assert(protocolNode->getKind() == Node::Kind::Protocol);
352-
}
353-
354-
return protocolNode;
355-
}
356-
#endif
357-
358-
return _buildDemanglingForContext(protocol.getSwiftProtocol(), {}, Dem);
359-
}
360-
361319
// Build a demangled type tree for a type.
362320
//
363321
// FIXME: This should use MetadataReader.h.
@@ -403,7 +361,48 @@ swift::_swift_buildDemanglingForMetadata(const Metadata *type,
403361
// its canonical ordering of protocols.
404362

405363
for (auto protocol : protocols) {
406-
auto protocolNode = _buildDemanglingForProtocolDescriptor(protocol, Dem);
364+
#if SWIFT_OBJC_INTEROP
365+
if (protocol.isObjC()) {
366+
// The protocol name is mangled as a type symbol, with the _Tt prefix.
367+
StringRef ProtoName(protocol.getName());
368+
NodePointer protocolNode = Dem.demangleSymbol(ProtoName);
369+
370+
// ObjC protocol names aren't mangled.
371+
if (!protocolNode) {
372+
auto module = Dem.createNode(Node::Kind::Module,
373+
MANGLING_MODULE_OBJC);
374+
auto node = Dem.createNode(Node::Kind::Protocol);
375+
node->addChild(module, Dem);
376+
node->addChild(Dem.createNode(Node::Kind::Identifier, ProtoName),
377+
Dem);
378+
auto typeNode = Dem.createNode(Node::Kind::Type);
379+
typeNode->addChild(node, Dem);
380+
type_list->addChild(typeNode, Dem);
381+
continue;
382+
}
383+
384+
// Dig out the protocol node.
385+
// Global -> (Protocol|TypeMangling)
386+
protocolNode = protocolNode->getChild(0);
387+
if (protocolNode->getKind() == Node::Kind::TypeMangling) {
388+
protocolNode = protocolNode->getChild(0); // TypeMangling -> Type
389+
protocolNode = protocolNode->getChild(0); // Type -> ProtocolList
390+
protocolNode = protocolNode->getChild(0); // ProtocolList -> TypeList
391+
protocolNode = protocolNode->getChild(0); // TypeList -> Type
392+
393+
assert(protocolNode->getKind() == Node::Kind::Type);
394+
assert(protocolNode->getChild(0)->getKind() == Node::Kind::Protocol);
395+
} else {
396+
assert(protocolNode->getKind() == Node::Kind::Protocol);
397+
}
398+
399+
type_list->addChild(protocolNode, Dem);
400+
continue;
401+
}
402+
#endif
403+
404+
auto protocolNode =
405+
_buildDemanglingForContext(protocol.getSwiftProtocol(), { }, Dem);
407406
if (!protocolNode)
408407
return nullptr;
409408

@@ -445,51 +444,7 @@ swift::_swift_buildDemanglingForMetadata(const Metadata *type,
445444
return proto_list;
446445
}
447446
case MetadataKind::ExtendedExistential: {
448-
auto exis = static_cast<const ExtendedExistentialTypeMetadata *>(type);
449-
auto genSig = exis->Shape->getGeneralizationSignature();
450-
const unsigned selfParamIdx = genSig.getParams().size();
451-
auto node = Dem.createNode(Node::Kind::ParameterizedProtocol);
452-
for (const auto &reqt :
453-
exis->Shape->getRequirementSignature().getRequirements()) {
454-
if (reqt.getKind() != GenericRequirementKind::Protocol) {
455-
continue;
456-
}
457-
458-
if (!reqt.Flags.hasKeyArgument()) {
459-
continue;
460-
}
461-
462-
auto lhsTypeNode = Dem.demangleType(reqt.getParam());
463-
if (!lhsTypeNode || lhsTypeNode->getKind() != Node::Kind::Type ||
464-
!lhsTypeNode->hasChildren() ||
465-
lhsTypeNode->getChild(0)->getKind() !=
466-
Node::Kind::DependentGenericParamType ||
467-
lhsTypeNode->getChild(0)->getNumChildren() != 2) {
468-
continue;
469-
}
470-
auto index = lhsTypeNode->getChild(0)->getChild(1)->getIndex();
471-
if (index + 1 != selfParamIdx)
472-
continue;
473-
474-
auto *protocolNode =
475-
_buildDemanglingForProtocolDescriptor(reqt.getProtocol(), Dem);
476-
if (!protocolNode)
477-
continue;
478-
479-
node->addChild(protocolNode, Dem);
480-
}
481-
482-
const unsigned shapeArgumentCount =
483-
exis->Shape->getGenSigArgumentLayoutSizeInWords();
484-
auto type_list = Dem.createNode(Node::Kind::TypeList);
485-
for (unsigned i = 0; i < shapeArgumentCount; ++i) {
486-
auto genArg = exis->getGeneralizationArguments()[i];
487-
auto eltType =
488-
_swift_buildDemanglingForMetadata((const Metadata *)genArg, Dem);
489-
type_list->addChild(eltType, Dem);
490-
}
491-
node->addChild(type_list, Dem);
492-
return node;
447+
swift_unreachable("Extended existentials not supported");
493448
}
494449
case MetadataKind::ExistentialMetatype: {
495450
auto metatype = static_cast<const ExistentialMetatypeMetadata *>(type);

stdlib/public/runtime/DynamicCast.cpp

Lines changed: 158 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1696,10 +1696,56 @@ tryCastUnwrappingExistentialSource(
16961696
return tryCast(destLocation, destType,
16971697
srcInnerValue, srcInnerType,
16981698
destFailureType, srcFailureType,
1699-
takeOnSuccess & (srcInnerValue == srcValue),
1699+
takeOnSuccess && (srcInnerValue == srcValue),
17001700
mayDeferChecks);
17011701
}
17021702

1703+
static DynamicCastResult tryCastUnwrappingExtendedExistentialSource(
1704+
OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *srcValue,
1705+
const Metadata *srcType, const Metadata *&destFailureType,
1706+
const Metadata *&srcFailureType, bool takeOnSuccess, bool mayDeferChecks) {
1707+
assert(srcType != destType);
1708+
assert(srcType->getKind() == MetadataKind::ExtendedExistential);
1709+
1710+
auto srcExistentialType = cast<ExtendedExistentialTypeMetadata>(srcType);
1711+
1712+
// Unpack the existential content
1713+
const Metadata *srcInnerType = nullptr;
1714+
OpaqueValue *srcInnerValue = nullptr;
1715+
switch (srcExistentialType->Shape->Flags.getSpecialKind()) {
1716+
case ExtendedExistentialTypeShape::SpecialKind::None: {
1717+
auto opaqueContainer =
1718+
reinterpret_cast<OpaqueExistentialContainer *>(srcValue);
1719+
srcInnerType = opaqueContainer->Type;
1720+
srcInnerValue = const_cast<OpaqueValue *>(opaqueContainer->projectValue());
1721+
break;
1722+
}
1723+
case ExtendedExistentialTypeShape::SpecialKind::Class: {
1724+
auto classContainer =
1725+
reinterpret_cast<ClassExistentialContainer *>(srcValue);
1726+
srcInnerType = swift_getObjectType((HeapObject *)classContainer->Value);
1727+
srcInnerValue = reinterpret_cast<OpaqueValue *>(&classContainer->Value);
1728+
break;
1729+
}
1730+
case ExtendedExistentialTypeShape::SpecialKind::Metatype: {
1731+
auto srcExistentialContainer =
1732+
reinterpret_cast<ExistentialMetatypeContainer *>(srcValue);
1733+
srcInnerType = swift_getMetatypeMetadata(srcExistentialContainer->Value);
1734+
srcInnerValue = reinterpret_cast<OpaqueValue *>(&srcExistentialContainer->Value);
1735+
break;
1736+
}
1737+
case ExtendedExistentialTypeShape::SpecialKind::ExplicitLayout: {
1738+
swift_unreachable("Explicit layout not yet implemented");
1739+
break;
1740+
}
1741+
}
1742+
1743+
srcFailureType = srcInnerType;
1744+
return tryCast(destLocation, destType, srcInnerValue, srcInnerType,
1745+
destFailureType, srcFailureType,
1746+
takeOnSuccess & (srcInnerValue == srcValue), mayDeferChecks);
1747+
}
1748+
17031749
static DynamicCastResult
17041750
tryCastUnwrappingExistentialMetatypeSource(
17051751
OpaqueValue *destLocation, const Metadata *destType,
@@ -1723,6 +1769,103 @@ tryCastUnwrappingExistentialMetatypeSource(
17231769
mayDeferChecks);
17241770
}
17251771

1772+
1773+
static DynamicCastResult tryCastToExtendedExistential(
1774+
OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *srcValue,
1775+
const Metadata *srcType, const Metadata *&destFailureType,
1776+
const Metadata *&srcFailureType, bool takeOnSuccess, bool mayDeferChecks) {
1777+
assert(srcType != destType);
1778+
assert(destType->getKind() == MetadataKind::ExtendedExistential);
1779+
1780+
auto destExistentialType = cast<ExtendedExistentialTypeMetadata>(destType);
1781+
auto *destExistentialShape = destExistentialType->Shape;
1782+
const unsigned shapeArgumentCount =
1783+
destExistentialShape->getGenSigArgumentLayoutSizeInWords();
1784+
1785+
llvm::SmallVector<const void *, 8> allGenericArgsVec;
1786+
unsigned witnessesMark = 0;
1787+
{
1788+
// Line up the arguments to the requirement signature.
1789+
auto genArgs = destExistentialType->getGeneralizationArguments();
1790+
allGenericArgsVec.append(genArgs, genArgs + shapeArgumentCount);
1791+
// Tack on the `Self` argument.
1792+
allGenericArgsVec.push_back((const void *)srcType);
1793+
// Mark the point where the generic arguments end.
1794+
// _checkGenericRequirements is going to fill in a set of witness tables
1795+
// after that.
1796+
witnessesMark = allGenericArgsVec.size();
1797+
1798+
SubstGenericParametersFromMetadata substitutions(destExistentialShape,
1799+
allGenericArgsVec.data());
1800+
// Verify the requirements in the requirement signature against the
1801+
// arguments from the source value.
1802+
auto error = swift::_checkGenericRequirements(
1803+
destExistentialShape->getRequirementSignature().getRequirements(),
1804+
allGenericArgsVec,
1805+
[&substitutions](unsigned depth, unsigned index) {
1806+
return substitutions.getMetadata(depth, index);
1807+
},
1808+
[](const Metadata *type, unsigned index) -> const WitnessTable * {
1809+
swift_unreachable("Resolution of witness tables is not supported");
1810+
});
1811+
if (error)
1812+
return DynamicCastResult::Failure;
1813+
}
1814+
1815+
OpaqueValue *destBox = nullptr;
1816+
const WitnessTable **destWitnesses = nullptr;
1817+
switch (destExistentialShape->Flags.getSpecialKind()) {
1818+
case ExtendedExistentialTypeShape::SpecialKind::None: {
1819+
auto destExistential =
1820+
reinterpret_cast<OpaqueExistentialContainer *>(destLocation);
1821+
1822+
// Allocate a box and fill in the type information.
1823+
destExistential->Type = srcType;
1824+
destBox = srcType->allocateBoxForExistentialIn(&destExistential->Buffer);
1825+
destWitnesses = destExistential->getWitnessTables();
1826+
break;
1827+
}
1828+
case ExtendedExistentialTypeShape::SpecialKind::Class: {
1829+
auto destExistential =
1830+
reinterpret_cast<ClassExistentialContainer *>(destLocation);
1831+
destBox = reinterpret_cast<OpaqueValue *>(&destExistential->Value);
1832+
destWitnesses = destExistential->getWitnessTables();
1833+
break;
1834+
}
1835+
case ExtendedExistentialTypeShape::SpecialKind::Metatype: {
1836+
auto destExistential =
1837+
reinterpret_cast<ExistentialMetatypeContainer *>(destLocation);
1838+
destBox = reinterpret_cast<OpaqueValue *>(&destExistential->Value);
1839+
destWitnesses = destExistential->getWitnessTables();
1840+
break;
1841+
}
1842+
case ExtendedExistentialTypeShape::SpecialKind::ExplicitLayout:
1843+
swift_unreachable("Witnesses for explicit layout not yet implemented");
1844+
}
1845+
1846+
// Fill in the trailing set of witness tables.
1847+
const unsigned numWitnessTables = allGenericArgsVec.size() - witnessesMark;
1848+
assert(numWitnessTables ==
1849+
llvm::count_if(destExistentialShape->getRequirementSignature().getRequirements(),
1850+
[](const auto &req) -> bool {
1851+
return req.getKind() ==
1852+
GenericRequirementKind::Protocol;
1853+
}));
1854+
for (unsigned i = 0; i < numWitnessTables; ++i) {
1855+
const auto witness = i + witnessesMark;
1856+
destWitnesses[i] =
1857+
reinterpret_cast<const WitnessTable *>(allGenericArgsVec[witness]);
1858+
}
1859+
1860+
if (takeOnSuccess) {
1861+
srcType->vw_initializeWithTake(destBox, srcValue);
1862+
return DynamicCastResult::SuccessViaTake;
1863+
} else {
1864+
srcType->vw_initializeWithCopy(destBox, srcValue);
1865+
return DynamicCastResult::SuccessViaCopy;
1866+
}
1867+
}
1868+
17261869
/******************************************************************************/
17271870
/**************************** Opaque Destination ******************************/
17281871
/******************************************************************************/
@@ -2007,12 +2150,14 @@ static tryCastFunctionType *selectCasterForDest(const Metadata *destType) {
20072150
swift_unreachable(
20082151
"Unknown existential type representation in dynamic cast dispatch");
20092152
}
2153+
case MetadataKind::ExtendedExistential:
2154+
return tryCastToExtendedExistential;
20102155
case MetadataKind::Metatype:
2011-
return tryCastToMetatype;
2012-
case MetadataKind::ObjCClassWrapper:
2156+
return tryCastToMetatype;
2157+
case MetadataKind::ObjCClassWrapper:
20132158
return tryCastToObjectiveCClass;
20142159
case MetadataKind::ExistentialMetatype:
2015-
return tryCastToExistentialMetatype;
2160+
return tryCastToExistentialMetatype;
20162161
case MetadataKind::HeapLocalVariable:
20172162
case MetadataKind::HeapGenericLocalVariable:
20182163
case MetadataKind::ErrorObject:
@@ -2170,6 +2315,15 @@ tryCast(
21702315
break;
21712316
}
21722317

2318+
case MetadataKind::ExtendedExistential: {
2319+
auto subcastResult = tryCastUnwrappingExtendedExistentialSource(
2320+
destLocation, destType, srcValue, srcType, destFailureType,
2321+
srcFailureType, takeOnSuccess, mayDeferChecks);
2322+
if (isSuccess(subcastResult)) {
2323+
return subcastResult;
2324+
}
2325+
break;
2326+
}
21732327
default:
21742328
break;
21752329
}

stdlib/public/runtime/Metadata.cpp

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3980,32 +3980,6 @@ ExistentialTypeMetadata::projectValue(const OpaqueValue *container) const {
39803980
"Unhandled ExistentialTypeRepresentation in switch.");
39813981
}
39823982

3983-
template <>
3984-
const OpaqueValue *ExtendedExistentialTypeMetadata::projectValue(
3985-
const OpaqueValue *container) const {
3986-
switch (Shape->Flags.getSpecialKind()) {
3987-
case ExtendedExistentialTypeShape::SpecialKind::None: {
3988-
auto *opaqueContainer =
3989-
reinterpret_cast<const OpaqueExistentialContainer *>(container);
3990-
return opaqueContainer->projectValue();
3991-
}
3992-
case ExtendedExistentialTypeShape::SpecialKind::Class: {
3993-
auto classContainer =
3994-
reinterpret_cast<const ClassExistentialContainer *>(container);
3995-
return reinterpret_cast<const OpaqueValue *>(&classContainer->Value);
3996-
}
3997-
case ExtendedExistentialTypeShape::SpecialKind::Metatype: {
3998-
auto *metatypeContainer =
3999-
reinterpret_cast<const ExistentialMetatypeContainer *>(container);
4000-
return reinterpret_cast<const OpaqueValue *>(&metatypeContainer->Value);
4001-
}
4002-
case ExtendedExistentialTypeShape::SpecialKind::ExplicitLayout:
4003-
swift_unreachable("ExplicitLayout not yet handled.");
4004-
}
4005-
4006-
swift_unreachable("Unhandled ExistentialTypeRepresentation in switch.");
4007-
}
4008-
40093983
template<> const Metadata *
40103984
ExistentialTypeMetadata::getDynamicType(const OpaqueValue *container) const {
40113985
switch (getRepresentation()) {

0 commit comments

Comments
 (0)