NCGenerics: enforce same-source conformance rule

SE-427 says the conformance to Copyable must appear in the same source
file as the nominal type.

resolves rdar://131486561
This commit is contained in:
Kavon Farvardin
2024-07-10 14:02:10 -07:00
parent 9aa7463175
commit 233742a565
4 changed files with 65 additions and 0 deletions

View File

@@ -7820,6 +7820,9 @@ WARNING(suppress_already_suppressed_protocol,none,
ERROR(extension_conforms_to_invertible_and_others, none,
"conformance to '%0' must be declared in a separate extension",
(StringRef))
ERROR(invertible_conformance_other_source_file,none,
"conformance to '%0' must occur in the same source file as %kind1",
(StringRef, const ValueDecl *))
// -- older ones below --
ERROR(noncopyable_parameter_requires_ownership, none,

View File

@@ -144,6 +144,16 @@ static void checkInvertibleConformanceCommon(DeclContext *dc,
conformanceLoc = normalConf->getLoc();
assert(conformanceLoc);
// Conformance must be defined in the same source file as the nominal.
auto conformanceDC = concrete->getDeclContext();
if (auto *sourceFile = conformanceDC->getOutermostParentSourceFile()) {
if (sourceFile != nominalDecl->getOutermostParentSourceFile()) {
ctx.Diags.diagnose(conformanceLoc,
diag::invertible_conformance_other_source_file,
getInvertibleProtocolKindName(ip), nominalDecl);
}
}
auto condReqs = normalConf->getConditionalRequirements();
hasUnconditionalConformance = condReqs.empty();
auto *thisProto = normalConf->getProtocol();

View File

@@ -0,0 +1,32 @@
// RUN: %empty-directory(%t)
// RUN: split-file %s %t
//// Ensure we cannot add the conformance in a different module.
// RUN: %target-build-swift \
// RUN: -swift-version 5 \
// RUN: -emit-module \
// RUN: -emit-module-path %t/GardenKit.swiftmodule \
// RUN: -emit-module-interface-path %t/GardenKit.swiftinterface \
// RUN: -enable-library-evolution \
// RUN: -module-name=GardenKit \
// RUN: %t/GardenKit.swift
// RUN: %target-swift-frontend \
// RUN: -typecheck -verify \
// RUN: -I %t \
// RUN: %t/Visitor.swift
//--- GardenKit.swift
public struct Garden<Plant: ~Copyable>: ~Copyable {
public let plant: Plant
public init(_ p: consuming Plant) { plant = p }
}
//--- Visitor.swift
import GardenKit
// expected-error@+1 {{conformance to 'Copyable' must occur in the same source file as generic struct 'Garden'}}
extension Garden: @retroactive Copyable where Plant: Copyable {}

View File

@@ -0,0 +1,20 @@
// RUN: %empty-directory(%t)
// RUN: split-file %s %t
//// Ensure we cannot add the conformance in a different source file.
// RUN: %target-swift-frontend \
// RUN: -typecheck -verify \
// RUN: %t/Visitor.swift %t/GardenKit.swift
//--- GardenKit.swift
public struct Garden<Plant: ~Copyable>: ~Copyable {
public let plant: Plant
public init(_ p: consuming Plant) { plant = p }
}
//--- Visitor.swift
// expected-error@+1 {{conformance to 'Copyable' must occur in the same source file as generic struct 'Garden'}}
extension Garden: Copyable where Plant: Copyable {}