Skip to content

Commit 84b309d

Browse files
committed
NCGenerics: conformances can depend on Copyable
1 parent 19933d0 commit 84b309d

File tree

2 files changed

+26
-2
lines changed

2 files changed

+26
-2
lines changed

Diff for: lib/Sema/TypeCheckProtocol.cpp

+9-2
Original file line numberDiff line numberDiff line change
@@ -2210,6 +2210,13 @@ static bool hasAdditionalSemanticChecks(ProtocolDecl *proto) {
22102210
return proto->isSpecificProtocol(KnownProtocolKind::Sendable);
22112211
}
22122212

2213+
/// Determine whether a conformance to this protocol can be determined at
2214+
/// runtime for an arbitrary type.
2215+
static bool hasRuntimeConformanceInfo(ProtocolDecl *proto) {
2216+
return !proto->isMarkerProtocol()
2217+
|| proto->isSpecificProtocol(KnownProtocolKind::Copyable);
2218+
}
2219+
22132220
static void ensureRequirementsAreSatisfied(ASTContext &ctx,
22142221
NormalProtocolConformance *conformance);
22152222

@@ -2354,11 +2361,11 @@ checkIndividualConformance(NormalProtocolConformance *conformance) {
23542361

23552362
// If the protocol to which we are conditionally conforming is not a marker
23562363
// protocol, the conditional requirements must not involve conformance to a
2357-
// marker protocol. We cannot evaluate such a conformance at runtime.
2364+
// protocol that cannot be evaluated at runtime, like most marker protocols.
23582365
if (!Proto->isMarkerProtocol()) {
23592366
for (const auto &req : conditionalReqs) {
23602367
if (req.getKind() == RequirementKind::Conformance &&
2361-
req.getProtocolDecl()->isMarkerProtocol()) {
2368+
!hasRuntimeConformanceInfo(req.getProtocolDecl())) {
23622369
Context.Diags.diagnose(
23632370
ComplainLoc, diag::marker_protocol_conditional_conformance,
23642371
Proto->getName(), req.getFirstType(),

Diff for: test/Generics/inverse_generics.swift

+17
Original file line numberDiff line numberDiff line change
@@ -462,3 +462,20 @@ func checkExistentials() {
462462
let _: any Copyable & ~Copyable = 1 // expected-error {{composition cannot contain '~Copyable' when another member requires 'Copyable'}}
463463
let _: any Escapable & ~Escapable = 1 // expected-error {{composition cannot contain '~Escapable' when another member requires 'Escapable'}}
464464
}
465+
466+
// Conformances can be conditional on whether a generic parameter is Copyable
467+
protocol Arbitrary {}
468+
protocol AnotherOne {}
469+
struct UnethicalPointer<Pointee: ~Copyable> {}
470+
extension UnethicalPointer: Arbitrary {}
471+
extension UnethicalPointer: AnotherOne where Pointee: Copyable {}
472+
473+
struct StillIllegal1<Pointee: ~Escapable> {}
474+
extension StillIllegal1: Arbitrary {}
475+
// expected-error@-1 {{conditional conformance to non-marker protocol 'Arbitrary' cannot depend on conformance of 'Pointee' to marker protocol 'Escapable'}}
476+
extension StillIllegal1: AnotherOne where Pointee: Escapable {}
477+
// expected-error@-1 {{conditional conformance to non-marker protocol 'AnotherOne' cannot depend on conformance of 'Pointee' to marker protocol 'Escapable'}}
478+
479+
struct SillIllegal2<Pointee> {}
480+
extension SillIllegal2: Arbitrary where Pointee: Sendable {}
481+
// expected-error@-1 {{conditional conformance to non-marker protocol 'Arbitrary' cannot depend on conformance of 'Pointee' to marker protocol 'Sendable'}}

0 commit comments

Comments
 (0)