Skip to content

Commit 9a7f821

Browse files
committed
Fixup Extended Existential Metatype Casts
The fix here is two-fold: 1) Teach SILGen that it cannot use the scalar casting paths for extended existentials 2) Teach the runtime casting entrypoint to unwrap as much metatype structure as possible before arriving at a 'Self' type bound for the requirement checking paths. The code here mirrors the destructuring check we're doing in remote mirrors. rdar://95166916
1 parent e063528 commit 9a7f821

File tree

4 files changed

+34
-5
lines changed

4 files changed

+34
-5
lines changed

lib/IRGen/GenCast.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -848,7 +848,7 @@ void irgen::emitScalarExistentialDowncast(IRGenFunction &IGF,
848848
/// that the actual value isn't changed in any way, thus preserving its
849849
/// reference identity.
850850
///
851-
/// These restrictions are set by canUseScalarCheckedCastInstructions.
851+
/// These restrictions are set by \c canSILUseScalarCheckedCastInstructions.
852852
/// Essentially, both the source and target types must be one of:
853853
/// - a (possibly generic) concrete class type,
854854
/// - a class-bounded archetype,

lib/SIL/Utils/DynamicCasts.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1311,6 +1311,14 @@ bool swift::canSILUseScalarCheckedCastInstructions(SILModule &M,
13111311
bool swift::canIRGenUseScalarCheckedCastInstructions(SILModule &M,
13121312
CanType sourceFormalType,
13131313
CanType targetFormalType) {
1314+
// If the cast involves any kind of generalized existential we
1315+
// need to use the indirect-cast path to handle checking the extra
1316+
// constraints there as the scalar path does not (yet) know how to do it.
1317+
if (sourceFormalType->hasParameterizedExistential() ||
1318+
targetFormalType->hasParameterizedExistential()) {
1319+
return false;
1320+
}
1321+
13141322
// Look through one level of optionality on the source.
13151323
auto objectType = sourceFormalType;
13161324
if (auto type = objectType.getOptionalObjectType())

stdlib/public/runtime/DynamicCast.cpp

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1780,6 +1780,29 @@ static DynamicCastResult tryCastToExtendedExistential(
17801780
auto *destExistentialShape = destExistentialType->Shape;
17811781
const unsigned shapeArgumentCount =
17821782
destExistentialShape->getGenSigArgumentLayoutSizeInWords();
1783+
const Metadata *selfType = srcType;
1784+
1785+
// If we have a type expression to look into, unwrap as much metatype
1786+
// structure as possible so we can reach the type metadata for the 'Self'
1787+
// parameter.
1788+
if (destExistentialShape->Flags.hasTypeExpression()) {
1789+
Demangler dem;
1790+
auto *node = dem.demangleType(destExistentialShape->getTypeExpression()->name.get());
1791+
if (!node)
1792+
return DynamicCastResult::Failure;
1793+
1794+
while (node->getKind() == Demangle::Node::Kind::Type &&
1795+
node->getNumChildren() &&
1796+
node->getChild(0)->getKind() == Demangle::Node::Kind::Metatype &&
1797+
node->getChild(0)->getNumChildren()) {
1798+
auto *metatypeMetadata = dyn_cast<MetatypeMetadata>(selfType);
1799+
if (!metatypeMetadata)
1800+
return DynamicCastResult::Failure;
1801+
1802+
selfType = metatypeMetadata->InstanceType;
1803+
node = node->getChild(0)->getChild(0);
1804+
}
1805+
}
17831806

17841807
llvm::SmallVector<const void *, 8> allGenericArgsVec;
17851808
unsigned witnessesMark = 0;
@@ -1788,7 +1811,7 @@ static DynamicCastResult tryCastToExtendedExistential(
17881811
auto genArgs = destExistentialType->getGeneralizationArguments();
17891812
allGenericArgsVec.append(genArgs, genArgs + shapeArgumentCount);
17901813
// Tack on the `Self` argument.
1791-
allGenericArgsVec.push_back((const void *)srcType);
1814+
allGenericArgsVec.push_back((const void *)selfType);
17921815
// Mark the point where the generic arguments end.
17931816
// _checkGenericRequirements is going to fill in a set of witness tables
17941817
// after that.

test/Casting/ParameterizedExistentials.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,7 @@ tests.test("Parameterized existential casting basics work") {
8282
expectNil(d)
8383
}
8484

85-
tests.test("Metatype existential casting basics work")
86-
.xfail(.custom({ true }, reason: "IRGen peepholes these casts"))
87-
.code {
85+
tests.test("Metatype existential casting basics work") {
8886
let a = GenericHolder<Int>.self as any Holder<Int>.Type
8987
let b = GenericHolder<Int>.self as! any Holder<Int>.Type
9088
expectTrue(a == b)

0 commit comments

Comments
 (0)