Skip to content

Commit e063528

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 8e7733d commit e063528

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
@@ -1695,10 +1695,56 @@ tryCastUnwrappingExistentialSource(
16951695
return tryCast(destLocation, destType,
16961696
srcInnerValue, srcInnerType,
16971697
destFailureType, srcFailureType,
1698-
takeOnSuccess & (srcInnerValue == srcValue),
1698+
takeOnSuccess && (srcInnerValue == srcValue),
16991699
mayDeferChecks);
17001700
}
17011701

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

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

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

stdlib/public/runtime/Metadata.cpp

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

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

0 commit comments

Comments
 (0)