Skip to content

Commit 0927c9f

Browse files
committed
Restrict implicit opening of existentials based on the generic function's requirements
Rather than looking solely at the existential argument of a generic function to determine whether it self-conforms, compare the existential argument against each of the protocols to which the corresponding generic parameter conforms. This better models when the existential value itself will successfully meet the requirements of the generic function, and therefore not require opening. This provides far better source compatibility by not changing semantics of existing, well-formed calls, and eliminates the need to special-case CoW-related operations in the standard library.
1 parent efd1965 commit 0927c9f

File tree

2 files changed

+26
-26
lines changed

2 files changed

+26
-26
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1501,32 +1501,6 @@ shouldOpenExistentialCallArgument(
15011501
if (!argTy->isAnyExistentialType())
15021502
return None;
15031503

1504-
1505-
// If the existential argument type conforms to all of its protocol
1506-
// requirements, don't open the existential.
1507-
{
1508-
Type existentialObjectType;
1509-
if (auto existentialMetaTy = argTy->getAs<ExistentialMetatypeType>())
1510-
existentialObjectType = existentialMetaTy->getInstanceType();
1511-
else
1512-
existentialObjectType = argTy;
1513-
auto layout = existentialObjectType->getExistentialLayout();
1514-
auto module = cs.DC->getParentModule();
1515-
bool containsNonSelfConformance = false;
1516-
for (auto proto : layout.getProtocols()) {
1517-
auto protoDecl = proto->getDecl();
1518-
auto conformance = module->lookupExistentialConformance(
1519-
existentialObjectType, protoDecl);
1520-
if (conformance.isInvalid()) {
1521-
containsNonSelfConformance = true;
1522-
break;
1523-
}
1524-
}
1525-
1526-
if (!containsNonSelfConformance)
1527-
return None;
1528-
}
1529-
15301504
auto param = getParameterAt(callee, paramIdx);
15311505
if (!param)
15321506
return None;
@@ -1568,6 +1542,31 @@ shouldOpenExistentialCallArgument(
15681542
genericSig.getGenericParams().back()->getDepth())
15691543
return None;
15701544

1545+
// If the existential argument conforms to all of protocol requirements on
1546+
// the formal parameter's type, don't open.
1547+
// If all of the conformance requirements on the formal parameter's type
1548+
// are self-conforming, don't open.
1549+
{
1550+
Type existentialObjectType;
1551+
if (auto existentialMetaTy = argTy->getAs<ExistentialMetatypeType>())
1552+
existentialObjectType = existentialMetaTy->getInstanceType();
1553+
else
1554+
existentialObjectType = argTy;
1555+
auto module = cs.DC->getParentModule();
1556+
bool containsNonSelfConformance = false;
1557+
for (auto proto : genericSig->getRequiredProtocols(genericParam)) {
1558+
auto conformance = module->lookupExistentialConformance(
1559+
existentialObjectType, proto);
1560+
if (conformance.isInvalid()) {
1561+
containsNonSelfConformance = true;
1562+
break;
1563+
}
1564+
}
1565+
1566+
if (!containsNonSelfConformance)
1567+
return None;
1568+
}
1569+
15711570
// Ensure that the formal parameter is only used in covariant positions,
15721571
// because it won't match anywhere else.
15731572
auto referenceInfo = findGenericParameterReferences(

test/Constraints/opened_existentials_suppression.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ func acceptsBoxType<T>(_ value: T.Type) { }
99
// CHECK: passBox
1010
// CHECK-NOT: open_existential_expr
1111
func passBox(p: P, obj: AnyObject, err: Error) {
12+
acceptsBox(p)
1213
acceptsBox(p as P)
1314
acceptsBox(p as! P)
1415
acceptsBox(p as? P)

0 commit comments

Comments
 (0)