mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
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
This commit is contained in:
@@ -2125,16 +2125,6 @@ public:
|
||||
return this->template getTrailingObjects<ConstTargetPointer<Runtime, void>>();
|
||||
}
|
||||
|
||||
public:
|
||||
/// Project the value pointer from an extended existential container of the
|
||||
/// type described by this metadata.
|
||||
const OpaqueValue *projectValue(const OpaqueValue *container) const;
|
||||
|
||||
OpaqueValue *projectValue(OpaqueValue *container) const {
|
||||
return const_cast<OpaqueValue *>(
|
||||
projectValue((const OpaqueValue *)container));
|
||||
}
|
||||
|
||||
public:
|
||||
static bool classof(const TargetMetadata<Runtime> *metadata) {
|
||||
return metadata->getKind() == MetadataKind::ExtendedExistential;
|
||||
|
||||
@@ -316,48 +316,6 @@ _buildDemanglingForNominalType(const Metadata *type, Demangle::Demangler &Dem) {
|
||||
return _buildDemanglingForContext(description, demangledGenerics, Dem);
|
||||
}
|
||||
|
||||
static Demangle::NodePointer
|
||||
_buildDemanglingForProtocolDescriptor(ProtocolDescriptorRef protocol,
|
||||
Demangle::Demangler &Dem) {
|
||||
#if SWIFT_OBJC_INTEROP
|
||||
if (protocol.isObjC()) {
|
||||
// The protocol name is mangled as a type symbol, with the _Tt prefix.
|
||||
StringRef ProtoName(protocol.getName());
|
||||
NodePointer protocolNode = Dem.demangleSymbol(ProtoName);
|
||||
|
||||
// ObjC protocol names aren't mangled.
|
||||
if (!protocolNode) {
|
||||
auto module = Dem.createNode(Node::Kind::Module, MANGLING_MODULE_OBJC);
|
||||
auto node = Dem.createNode(Node::Kind::Protocol);
|
||||
node->addChild(module, Dem);
|
||||
node->addChild(Dem.createNode(Node::Kind::Identifier, ProtoName), Dem);
|
||||
auto typeNode = Dem.createNode(Node::Kind::Type);
|
||||
typeNode->addChild(node, Dem);
|
||||
return typeNode;
|
||||
}
|
||||
|
||||
// Dig out the protocol node.
|
||||
// Global -> (Protocol|TypeMangling)
|
||||
protocolNode = protocolNode->getChild(0);
|
||||
if (protocolNode->getKind() == Node::Kind::TypeMangling) {
|
||||
protocolNode = protocolNode->getChild(0); // TypeMangling -> Type
|
||||
protocolNode = protocolNode->getChild(0); // Type -> ProtocolList
|
||||
protocolNode = protocolNode->getChild(0); // ProtocolList -> TypeList
|
||||
protocolNode = protocolNode->getChild(0); // TypeList -> Type
|
||||
|
||||
assert(protocolNode->getKind() == Node::Kind::Type);
|
||||
assert(protocolNode->getChild(0)->getKind() == Node::Kind::Protocol);
|
||||
} else {
|
||||
assert(protocolNode->getKind() == Node::Kind::Protocol);
|
||||
}
|
||||
|
||||
return protocolNode;
|
||||
}
|
||||
#endif
|
||||
|
||||
return _buildDemanglingForContext(protocol.getSwiftProtocol(), {}, Dem);
|
||||
}
|
||||
|
||||
// Build a demangled type tree for a type.
|
||||
//
|
||||
// FIXME: This should use MetadataReader.h.
|
||||
@@ -403,7 +361,48 @@ swift::_swift_buildDemanglingForMetadata(const Metadata *type,
|
||||
// its canonical ordering of protocols.
|
||||
|
||||
for (auto protocol : protocols) {
|
||||
auto protocolNode = _buildDemanglingForProtocolDescriptor(protocol, Dem);
|
||||
#if SWIFT_OBJC_INTEROP
|
||||
if (protocol.isObjC()) {
|
||||
// The protocol name is mangled as a type symbol, with the _Tt prefix.
|
||||
StringRef ProtoName(protocol.getName());
|
||||
NodePointer protocolNode = Dem.demangleSymbol(ProtoName);
|
||||
|
||||
// ObjC protocol names aren't mangled.
|
||||
if (!protocolNode) {
|
||||
auto module = Dem.createNode(Node::Kind::Module,
|
||||
MANGLING_MODULE_OBJC);
|
||||
auto node = Dem.createNode(Node::Kind::Protocol);
|
||||
node->addChild(module, Dem);
|
||||
node->addChild(Dem.createNode(Node::Kind::Identifier, ProtoName),
|
||||
Dem);
|
||||
auto typeNode = Dem.createNode(Node::Kind::Type);
|
||||
typeNode->addChild(node, Dem);
|
||||
type_list->addChild(typeNode, Dem);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Dig out the protocol node.
|
||||
// Global -> (Protocol|TypeMangling)
|
||||
protocolNode = protocolNode->getChild(0);
|
||||
if (protocolNode->getKind() == Node::Kind::TypeMangling) {
|
||||
protocolNode = protocolNode->getChild(0); // TypeMangling -> Type
|
||||
protocolNode = protocolNode->getChild(0); // Type -> ProtocolList
|
||||
protocolNode = protocolNode->getChild(0); // ProtocolList -> TypeList
|
||||
protocolNode = protocolNode->getChild(0); // TypeList -> Type
|
||||
|
||||
assert(protocolNode->getKind() == Node::Kind::Type);
|
||||
assert(protocolNode->getChild(0)->getKind() == Node::Kind::Protocol);
|
||||
} else {
|
||||
assert(protocolNode->getKind() == Node::Kind::Protocol);
|
||||
}
|
||||
|
||||
type_list->addChild(protocolNode, Dem);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
auto protocolNode =
|
||||
_buildDemanglingForContext(protocol.getSwiftProtocol(), { }, Dem);
|
||||
if (!protocolNode)
|
||||
return nullptr;
|
||||
|
||||
@@ -445,51 +444,7 @@ swift::_swift_buildDemanglingForMetadata(const Metadata *type,
|
||||
return proto_list;
|
||||
}
|
||||
case MetadataKind::ExtendedExistential: {
|
||||
auto exis = static_cast<const ExtendedExistentialTypeMetadata *>(type);
|
||||
auto genSig = exis->Shape->getGeneralizationSignature();
|
||||
const unsigned selfParamIdx = genSig.getParams().size();
|
||||
auto node = Dem.createNode(Node::Kind::ParameterizedProtocol);
|
||||
for (const auto &reqt :
|
||||
exis->Shape->getRequirementSignature().getRequirements()) {
|
||||
if (reqt.getKind() != GenericRequirementKind::Protocol) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!reqt.Flags.hasKeyArgument()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto lhsTypeNode = Dem.demangleType(reqt.getParam());
|
||||
if (!lhsTypeNode || lhsTypeNode->getKind() != Node::Kind::Type ||
|
||||
!lhsTypeNode->hasChildren() ||
|
||||
lhsTypeNode->getChild(0)->getKind() !=
|
||||
Node::Kind::DependentGenericParamType ||
|
||||
lhsTypeNode->getChild(0)->getNumChildren() != 2) {
|
||||
continue;
|
||||
}
|
||||
auto index = lhsTypeNode->getChild(0)->getChild(1)->getIndex();
|
||||
if (index + 1 != selfParamIdx)
|
||||
continue;
|
||||
|
||||
auto *protocolNode =
|
||||
_buildDemanglingForProtocolDescriptor(reqt.getProtocol(), Dem);
|
||||
if (!protocolNode)
|
||||
continue;
|
||||
|
||||
node->addChild(protocolNode, Dem);
|
||||
}
|
||||
|
||||
const unsigned shapeArgumentCount =
|
||||
exis->Shape->getGenSigArgumentLayoutSizeInWords();
|
||||
auto type_list = Dem.createNode(Node::Kind::TypeList);
|
||||
for (unsigned i = 0; i < shapeArgumentCount; ++i) {
|
||||
auto genArg = exis->getGeneralizationArguments()[i];
|
||||
auto eltType =
|
||||
_swift_buildDemanglingForMetadata((const Metadata *)genArg, Dem);
|
||||
type_list->addChild(eltType, Dem);
|
||||
}
|
||||
node->addChild(type_list, Dem);
|
||||
return node;
|
||||
swift_unreachable("Extended existentials not supported");
|
||||
}
|
||||
case MetadataKind::ExistentialMetatype: {
|
||||
auto metatype = static_cast<const ExistentialMetatypeMetadata *>(type);
|
||||
|
||||
@@ -1696,10 +1696,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);
|
||||
}
|
||||
|
||||
static DynamicCastResult
|
||||
tryCastUnwrappingExistentialMetatypeSource(
|
||||
OpaqueValue *destLocation, const Metadata *destType,
|
||||
@@ -1723,6 +1769,103 @@ 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();
|
||||
|
||||
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 *)srcType);
|
||||
// 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 ******************************/
|
||||
/******************************************************************************/
|
||||
@@ -2007,12 +2150,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;
|
||||
case MetadataKind::HeapLocalVariable:
|
||||
case MetadataKind::HeapGenericLocalVariable:
|
||||
case MetadataKind::ErrorObject:
|
||||
@@ -2170,6 +2315,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;
|
||||
}
|
||||
|
||||
@@ -3980,32 +3980,6 @@ ExistentialTypeMetadata::projectValue(const OpaqueValue *container) const {
|
||||
"Unhandled ExistentialTypeRepresentation in switch.");
|
||||
}
|
||||
|
||||
template <>
|
||||
const OpaqueValue *ExtendedExistentialTypeMetadata::projectValue(
|
||||
const OpaqueValue *container) const {
|
||||
switch (Shape->Flags.getSpecialKind()) {
|
||||
case ExtendedExistentialTypeShape::SpecialKind::None: {
|
||||
auto *opaqueContainer =
|
||||
reinterpret_cast<const OpaqueExistentialContainer *>(container);
|
||||
return opaqueContainer->projectValue();
|
||||
}
|
||||
case ExtendedExistentialTypeShape::SpecialKind::Class: {
|
||||
auto classContainer =
|
||||
reinterpret_cast<const ClassExistentialContainer *>(container);
|
||||
return reinterpret_cast<const OpaqueValue *>(&classContainer->Value);
|
||||
}
|
||||
case ExtendedExistentialTypeShape::SpecialKind::Metatype: {
|
||||
auto *metatypeContainer =
|
||||
reinterpret_cast<const ExistentialMetatypeContainer *>(container);
|
||||
return reinterpret_cast<const OpaqueValue *>(&metatypeContainer->Value);
|
||||
}
|
||||
case ExtendedExistentialTypeShape::SpecialKind::ExplicitLayout:
|
||||
swift_unreachable("ExplicitLayout not yet handled.");
|
||||
}
|
||||
|
||||
swift_unreachable("Unhandled ExistentialTypeRepresentation in switch.");
|
||||
}
|
||||
|
||||
template<> const Metadata *
|
||||
ExistentialTypeMetadata::getDynamicType(const OpaqueValue *container) const {
|
||||
switch (getRepresentation()) {
|
||||
|
||||
@@ -2374,49 +2374,32 @@ buildEnvironmentPath(
|
||||
unsigned SubstGenericParametersFromMetadata::buildShapePath(
|
||||
const TargetExtendedExistentialTypeShape<InProcess> *shape) const {
|
||||
unsigned totalParamCount = 0;
|
||||
unsigned totalKeyParamCount = 0;
|
||||
|
||||
auto genSig = shape->getGeneralizationSignature();
|
||||
if (!genSig.getParams().empty()) {
|
||||
bool hasNonKeyGenericParams = false;
|
||||
unsigned numKeyGenericParamsHere = 0;
|
||||
for (const auto &gp : genSig.getParams()) {
|
||||
if (gp.hasKeyArgument())
|
||||
numKeyGenericParamsHere++;
|
||||
else
|
||||
hasNonKeyGenericParams = true;
|
||||
}
|
||||
totalParamCount += numKeyGenericParamsHere;
|
||||
totalKeyParamCount += numKeyGenericParamsHere;
|
||||
descriptorPath.push_back(PathElement{genSig.getParams(), totalParamCount,
|
||||
totalParamCount += genSig.getParams().size();
|
||||
descriptorPath.push_back(PathElement{genSig.getParams(),
|
||||
totalParamCount,
|
||||
/*numKeyGenericParamsInParent*/ 0,
|
||||
numKeyGenericParamsHere,
|
||||
hasNonKeyGenericParams});
|
||||
(unsigned)genSig.getParams().size(),
|
||||
/*hasNonKeyGenericParams*/ false});
|
||||
}
|
||||
|
||||
const unsigned genSigParamCount = genSig.getParams().size();
|
||||
auto reqSig = shape->getRequirementSignature();
|
||||
assert(reqSig.getParams().size() > genSig.getParams().size());
|
||||
{
|
||||
bool hasNonKeyGenericParams = false;
|
||||
unsigned numKeyGenericParamsHere = 0;
|
||||
auto remainingParams = reqSig.getParams().drop_front(genSig.getParams().size());
|
||||
for (const auto &gp : remainingParams) {
|
||||
if (gp.hasKeyArgument())
|
||||
numKeyGenericParamsHere++;
|
||||
else
|
||||
hasNonKeyGenericParams = true;
|
||||
}
|
||||
totalParamCount += numKeyGenericParamsHere;
|
||||
totalKeyParamCount += numKeyGenericParamsHere;
|
||||
totalParamCount += remainingParams.size();
|
||||
descriptorPath.push_back(PathElement{remainingParams,
|
||||
totalParamCount,
|
||||
genSigParamCount,
|
||||
numKeyGenericParamsHere,
|
||||
hasNonKeyGenericParams});
|
||||
(unsigned)remainingParams.size(),
|
||||
/*hasNonKeyGenericParams*/ false});
|
||||
}
|
||||
|
||||
return totalKeyParamCount;
|
||||
// All parameters in this signature are key parameters.
|
||||
return totalParamCount;
|
||||
}
|
||||
|
||||
void SubstGenericParametersFromMetadata::setup() const {
|
||||
|
||||
116
test/Casting/ParameterizedExistentials.swift
Normal file
116
test/Casting/ParameterizedExistentials.swift
Normal file
@@ -0,0 +1,116 @@
|
||||
// ParameterizedExistentials.swift - Tests for class constant casts w/ Obj-C
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See https://swift.org/LICENSE.txt for license information
|
||||
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
///
|
||||
/// Tests for parameterized existential type conversions.
|
||||
///
|
||||
// -----------------------------------------------------------------------------
|
||||
// RUN: %empty-directory(%t)
|
||||
//
|
||||
// RUN: %target-build-swift -swift-version 5 -g -Onone -Xfrontend -disable-availability-checking -module-name a -c %s -o %t/ParameterizedExistentials.swift.Onone.o
|
||||
// RUN: %target-swiftc_driver %t/ParameterizedExistentials.swift.Onone.o -o %t/a.swift5.Onone.out
|
||||
// RUN: %target-codesign %t/a.swift5.Onone.out
|
||||
// RUN: %target-run %t/a.swift5.Onone.out
|
||||
//
|
||||
// RUN: %target-build-swift -swift-version 5 -g -O -Xfrontend -disable-availability-checking -module-name a -c %s -o %t/ParameterizedExistentials.swift.O.o
|
||||
// RUN: %target-swiftc_driver %t/ParameterizedExistentials.swift.O.o -o %t/a.swift5.O.out
|
||||
// RUN: %target-codesign %t/a.swift5.O.out
|
||||
// RUN: %target-run %t/a.swift5.O.out
|
||||
//
|
||||
// REQUIRES: executable_test
|
||||
// This test requires the new existential shape metadata accessors which are
|
||||
// not available in on-device runtimes, or in the back-deployment runtime.
|
||||
// UNSUPPORTED: use_os_stdlib
|
||||
// UNSUPPORTED: back_deployment_runtime
|
||||
|
||||
import Swift
|
||||
|
||||
import StdlibUnittest
|
||||
|
||||
protocol Holder<T> {
|
||||
associatedtype T
|
||||
var value: T { get }
|
||||
}
|
||||
|
||||
struct GenericHolder<T>: Holder {
|
||||
var value: T
|
||||
|
||||
init(value: T) { self.value = value}
|
||||
}
|
||||
|
||||
protocol PairType<T, U> {
|
||||
associatedtype T
|
||||
associatedtype U
|
||||
|
||||
var first: T { get }
|
||||
var second: U { get }
|
||||
}
|
||||
|
||||
struct Pair<T, U>: PairType {
|
||||
var value: (T, U)
|
||||
|
||||
var first: T { self.value.0 }
|
||||
var second: U { self.value.1 }
|
||||
|
||||
init(value: (T, U)) { self.value = value}
|
||||
}
|
||||
|
||||
final class ReferencePair<T, U>: PairType {
|
||||
var first: T
|
||||
var second: U
|
||||
|
||||
init(value: (T, U)) { (self.first, self.second) = value }
|
||||
}
|
||||
|
||||
let tests = TestSuite("ParameterizedExistentials")
|
||||
|
||||
tests.test("Parameterized existential casting basics work") {
|
||||
let a = GenericHolder(value: 5) as any Holder<Int>
|
||||
let b = GenericHolder(value: 5) as! any Holder<Int>
|
||||
expectEqual(a.value, b.value)
|
||||
let c = GenericHolder(value: 5) as? any Holder<Int>
|
||||
expectNotNil(c)
|
||||
let d = GenericHolder(value: 5) as? any Holder<String>
|
||||
expectNil(d)
|
||||
}
|
||||
|
||||
tests.test("Metatype existential casting basics work")
|
||||
.xfail(.custom({ true }, reason: "IRGen peepholes these casts"))
|
||||
.code {
|
||||
let a = GenericHolder<Int>.self as any Holder<Int>.Type
|
||||
let b = GenericHolder<Int>.self as! any Holder<Int>.Type
|
||||
expectTrue(a == b)
|
||||
let c = GenericHolder<Int>.self as? any Holder<Int>.Type
|
||||
expectNotNil(c)
|
||||
let d = GenericHolder<Int>.self as? any Holder<String>.Type
|
||||
expectNil(d)
|
||||
}
|
||||
|
||||
tests.test("Existential box should maintain identity") {
|
||||
let a = Pair(value: ("Hello", 42))
|
||||
var b/*ox*/ = a as? any PairType<String, Int>
|
||||
expectNotNil(b)
|
||||
expectEqual(a.value, (b!.first, b!.second))
|
||||
|
||||
let c = ReferencePair(value: ("Goodbye", 24))
|
||||
let d = c as? any PairType<String, Int>
|
||||
expectNotNil(d)
|
||||
|
||||
b = d!
|
||||
expectEqual(b!.first, d!.first)
|
||||
expectEqual(b!.second, d!.second)
|
||||
|
||||
let e = b as? ReferencePair<String, Int>
|
||||
expectNotNil(e)
|
||||
expectTrue(e! === c)
|
||||
}
|
||||
|
||||
runAllTests()
|
||||
@@ -43,4 +43,11 @@ ParameterizedProtocolsTestSuite.test("metadataEquality") {
|
||||
expectEqual(typeOne, typeTwo)
|
||||
}
|
||||
|
||||
ParameterizedProtocolsTestSuite.test("casting") {
|
||||
let a = GenericHolder(value: 5) as any Holder<Int>
|
||||
let b = GenericHolder(value: 5) as! any Holder<Int>
|
||||
expectEqual(a.value, b.value)
|
||||
}
|
||||
|
||||
runAllTests()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user