Skip to content

Commit e5d7885

Browse files
authored
Merge pull request #72788 from DougGregor/metadata-runtime-inverse-conformances-assoctype
Runtime checking for associated types conforming to invertible protocols
2 parents dea09e1 + ae01d20 commit e5d7885

File tree

6 files changed

+83
-12
lines changed

6 files changed

+83
-12
lines changed

lib/AST/ASTMangler.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2530,8 +2530,6 @@ void ASTMangler::appendModule(const ModuleDecl *module,
25302530
/// Mangle the name of a protocol as a substitution candidate.
25312531
void ASTMangler::appendProtocolName(const ProtocolDecl *protocol,
25322532
bool allowStandardSubstitution) {
2533-
assert(!protocol->getInvertibleProtocolKind() &&
2534-
"only inverse requirements are mangled");
25352533
assert(AllowMarkerProtocols || !protocol->isMarkerProtocol());
25362534

25372535
if (allowStandardSubstitution && tryAppendStandardSubstitution(protocol))

lib/IRGen/GenMeta.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6972,6 +6972,27 @@ GenericArgumentMetadata irgen::addGenericRequirements(
69726972
case RequirementKind::Conformance: {
69736973
auto protocol = requirement.getProtocolDecl();
69746974

6975+
// If this is an invertible protocol, encode it as an inverted protocol
6976+
// check with all but this protocol masked off.
6977+
if (auto invertible = protocol->getInvertibleProtocolKind()) {
6978+
++metadata.NumRequirements;
6979+
6980+
InvertibleProtocolSet mask(0xFFFF);
6981+
mask.remove(*invertible);
6982+
6983+
auto flags = GenericRequirementFlags(
6984+
GenericRequirementKind::InvertedProtocols,
6985+
/*key argument*/ false,
6986+
/* is parameter pack */false);
6987+
addGenericRequirement(IGM, B, metadata, sig, flags,
6988+
requirement.getFirstType(),
6989+
[&]{
6990+
B.addInt16(0xFFFF);
6991+
B.addInt16(mask.rawBits());
6992+
});
6993+
break;
6994+
}
6995+
69756996
// Marker protocols do not record generic requirements at all.
69766997
if (protocol->isMarkerProtocol()) {
69776998
break;

lib/SILOptimizer/Utils/CastOptimizer.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
//===----------------------------------------------------------------------===//
1818

1919
#include "swift/SILOptimizer/Utils/CastOptimizer.h"
20+
#include "swift/AST/ExistentialLayout.h"
2021
#include "swift/AST/GenericSignature.h"
2122
#include "swift/AST/Module.h"
2223
#include "swift/AST/SubstitutionMap.h"
@@ -1472,6 +1473,10 @@ static bool optimizeStaticallyKnownProtocolConformance(
14721473
if (Conformance.isInvalid())
14731474
return false;
14741475

1476+
auto layout = TargetType->getExistentialLayout();
1477+
if (layout.getProtocols().size() != 1)
1478+
return false;
1479+
14751480
SILBuilderWithScope B(Inst);
14761481
SmallVector<ProtocolConformanceRef, 1> NewConformances;
14771482
NewConformances.push_back(Conformance);

stdlib/public/runtime/ProtocolConformance.cpp

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1349,6 +1349,10 @@ bool swift::_swift_class_isSubclass(const Metadata *subclass,
13491349
return isSubclass(subclass, superclass);
13501350
}
13511351

1352+
static std::optional<TypeLookupError>
1353+
checkInvertibleRequirements(const Metadata *type,
1354+
InvertibleProtocolSet ignored);
1355+
13521356
static std::optional<TypeLookupError>
13531357
checkGenericRequirement(
13541358
const GenericRequirementDescriptor &req,
@@ -1445,8 +1449,10 @@ checkGenericRequirement(
14451449
}
14461450
case GenericRequirementKind::InvertedProtocols: {
14471451
uint16_t index = req.getInvertedProtocolsGenericParamIndex();
1448-
if (index == 0xFFFF)
1449-
return TYPE_LOOKUP_ERROR_FMT("unable to suppress protocols");
1452+
if (index == 0xFFFF) {
1453+
return checkInvertibleRequirements(subjectType,
1454+
req.getInvertedProtocols());
1455+
}
14501456

14511457
// Expand the suppression set so we can record these protocols.
14521458
if (index >= suppressed.size()) {
@@ -1613,8 +1619,18 @@ checkGenericPackRequirement(
16131619

16141620
case GenericRequirementKind::InvertedProtocols: {
16151621
uint16_t index = req.getInvertedProtocolsGenericParamIndex();
1616-
if (index == 0xFFFF)
1617-
return TYPE_LOOKUP_ERROR_FMT("unable to suppress protocols");
1622+
if (index == 0xFFFF) {
1623+
// Check that each pack element meets the invertible requirements.
1624+
for (size_t i = 0, e = subjectType.getNumElements(); i < e; ++i) {
1625+
const Metadata *elt = subjectType.getElements()[i];
1626+
1627+
if (auto error = checkInvertibleRequirements(
1628+
elt, req.getInvertedProtocols()))
1629+
return error;
1630+
}
1631+
1632+
return std::nullopt;
1633+
}
16181634

16191635
// Expand the suppression set so we can record these protocols.
16201636
if (index >= suppressed.size()) {
@@ -1632,10 +1648,6 @@ checkGenericPackRequirement(
16321648
(unsigned)req.getKind());
16331649
}
16341650

1635-
static std::optional<TypeLookupError>
1636-
checkInvertibleRequirements(const Metadata *type,
1637-
InvertibleProtocolSet ignored);
1638-
16391651
static std::optional<TypeLookupError>
16401652
checkInvertibleRequirementsStructural(const Metadata *type,
16411653
InvertibleProtocolSet ignored) {

test/Interpreter/moveonly_generics_casting.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,7 @@ func main() {
125125
attemptCall(Dog<Any>())
126126

127127
// CHECK-FIXME: failed to cast (attemptCall)
128-
typealias NoncopyableAny = ~Copyable
129-
// FIXME crashes: attemptCall(Dog<any NoncopyableAny>())
128+
// FIXME crashes: attemptCall(Dog<any ~Copyable>())
130129

131130
// CHECK: cast succeeded
132131
test_radar124171788(.nothing)
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// RUN: %target-run-simple-swift(-Xfrontend -sil-verify-all -enable-experimental-feature NoncopyableGenerics -enable-experimental-feature SuppressedAssociatedTypes)
2+
// RUN: %target-run-simple-swift(-O -Xfrontend -sil-verify-all -enable-experimental-feature NoncopyableGenerics -enable-experimental-feature SuppressedAssociatedTypes)
3+
4+
// REQUIRES: executable_test
5+
6+
// UNSUPPORTED: use_os_stdlib
7+
// UNSUPPORTED: back_deployment_runtime
8+
9+
protocol P: ~Copyable {
10+
associatedtype A: ~Copyable
11+
}
12+
13+
protocol Q: ~Copyable { }
14+
15+
struct X<T: P & ~Copyable> { }
16+
17+
extension X: Q where T: ~Copyable, T.A: Copyable { }
18+
19+
struct NC: ~Copyable { }
20+
21+
struct WithCopyable: P {
22+
typealias A = Int
23+
}
24+
25+
struct WithNonCopyable: P {
26+
typealias A = NC
27+
}
28+
29+
func tryCastToQ<T: P>(_: T.Type) -> Q? {
30+
let x = X<T>()
31+
return x as? Q
32+
}
33+
34+
precondition(tryCastToQ(_: WithCopyable.self) != nil)
35+
precondition(tryCastToQ(_: WithNonCopyable.self) == nil)
36+

0 commit comments

Comments
 (0)