Skip to content

Commit bbc02a5

Browse files
authored
Merge pull request #75141 from kavon/invertible-conformance-same-sourcefile
NCGenerics: enforce same-source conformance rule
2 parents d1847ff + 233742a commit bbc02a5

File tree

4 files changed

+65
-0
lines changed

4 files changed

+65
-0
lines changed

include/swift/AST/DiagnosticsSema.def

+3
Original file line numberDiff line numberDiff line change
@@ -7826,6 +7826,9 @@ WARNING(suppress_already_suppressed_protocol,none,
78267826
ERROR(extension_conforms_to_invertible_and_others, none,
78277827
"conformance to '%0' must be declared in a separate extension",
78287828
(StringRef))
7829+
ERROR(invertible_conformance_other_source_file,none,
7830+
"conformance to '%0' must occur in the same source file as %kind1",
7831+
(StringRef, const ValueDecl *))
78297832

78307833
// -- older ones below --
78317834
ERROR(noncopyable_parameter_requires_ownership, none,

lib/Sema/TypeCheckInvertible.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,16 @@ static void checkInvertibleConformanceCommon(DeclContext *dc,
144144
conformanceLoc = normalConf->getLoc();
145145
assert(conformanceLoc);
146146

147+
// Conformance must be defined in the same source file as the nominal.
148+
auto conformanceDC = concrete->getDeclContext();
149+
if (auto *sourceFile = conformanceDC->getOutermostParentSourceFile()) {
150+
if (sourceFile != nominalDecl->getOutermostParentSourceFile()) {
151+
ctx.Diags.diagnose(conformanceLoc,
152+
diag::invertible_conformance_other_source_file,
153+
getInvertibleProtocolKindName(ip), nominalDecl);
154+
}
155+
}
156+
147157
auto condReqs = normalConf->getConditionalRequirements();
148158
hasUnconditionalConformance = condReqs.empty();
149159
auto *thisProto = normalConf->getProtocol();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: split-file %s %t
3+
4+
//// Ensure we cannot add the conformance in a different module.
5+
6+
// RUN: %target-build-swift \
7+
// RUN: -swift-version 5 \
8+
// RUN: -emit-module \
9+
// RUN: -emit-module-path %t/GardenKit.swiftmodule \
10+
// RUN: -emit-module-interface-path %t/GardenKit.swiftinterface \
11+
// RUN: -enable-library-evolution \
12+
// RUN: -module-name=GardenKit \
13+
// RUN: %t/GardenKit.swift
14+
15+
// RUN: %target-swift-frontend \
16+
// RUN: -typecheck -verify \
17+
// RUN: -I %t \
18+
// RUN: %t/Visitor.swift
19+
20+
//--- GardenKit.swift
21+
22+
public struct Garden<Plant: ~Copyable>: ~Copyable {
23+
public let plant: Plant
24+
public init(_ p: consuming Plant) { plant = p }
25+
}
26+
27+
//--- Visitor.swift
28+
29+
import GardenKit
30+
31+
// expected-error@+1 {{conformance to 'Copyable' must occur in the same source file as generic struct 'Garden'}}
32+
extension Garden: @retroactive Copyable where Plant: Copyable {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: split-file %s %t
3+
4+
//// Ensure we cannot add the conformance in a different source file.
5+
6+
// RUN: %target-swift-frontend \
7+
// RUN: -typecheck -verify \
8+
// RUN: %t/Visitor.swift %t/GardenKit.swift
9+
10+
//--- GardenKit.swift
11+
12+
public struct Garden<Plant: ~Copyable>: ~Copyable {
13+
public let plant: Plant
14+
public init(_ p: consuming Plant) { plant = p }
15+
}
16+
17+
//--- Visitor.swift
18+
19+
// expected-error@+1 {{conformance to 'Copyable' must occur in the same source file as generic struct 'Garden'}}
20+
extension Garden: Copyable where Plant: Copyable {}

0 commit comments

Comments
 (0)