Skip to content

Commit e52d7a0

Browse files
committed
[AST] Choose an implied conformance source next to the type, if possible.
If a conformance to a protocol is implied by several other conformances (i.e. protocol P: Equatable {} and protocol Q: Equatable {} and a type declares conformance to both P and Q), we should choose a source that's in the same file as the type, if we can, because automatic synthesis of conformances (for Equatable, Hashable, etc.) only works in that case. Fixes rdar://problem/41852654.
1 parent e6d722a commit e52d7a0

File tree

5 files changed

+44
-0
lines changed

5 files changed

+44
-0
lines changed

lib/AST/ConformanceLookupTable.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -672,6 +672,19 @@ ConformanceLookupTable::Ordering ConformanceLookupTable::compareConformances(
672672
: Ordering::After;
673673
}
674674

675+
// If one of the conformances comes from the same file as the type
676+
// declaration, pick that one; this is so that conformance synthesis works if
677+
// there's any implied conformance in the same file as the type.
678+
auto NTD =
679+
lhs->getDeclContext()->getAsNominalTypeOrNominalTypeExtensionContext();
680+
auto typeSF = NTD->getParentSourceFile();
681+
if (typeSF) {
682+
if (typeSF == lhsSF)
683+
return Ordering::Before;
684+
if (typeSF == rhsSF)
685+
return Ordering::After;
686+
}
687+
675688
// Otherwise, pick the earlier file unit.
676689
auto lhsFileUnit
677690
= dyn_cast<FileUnit>(lhs->getDeclContext()->getModuleScopeContext());

test/Sema/Inputs/enum_conformance_synthesis_other.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,9 @@ enum GenericOtherFileNonconforming<T> {
2323
// expected-note@-1 {{type declared here}}
2424
case A(T)
2525
}
26+
27+
protocol ImplierOther: Equatable {}
28+
extension ImpliedMain: ImplierMain {}
29+
enum ImpliedOther: ImplierOther {
30+
case a(Int)
31+
}

test/Sema/Inputs/struct_equatable_hashable_other.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,7 @@ struct GenericOtherFileNonconforming<T> {
2222
// expected-note@-1{{type declared here}}
2323
let v: T
2424
}
25+
26+
protocol ImplierOther: Equatable {}
27+
extension ImpliedMain: ImplierOther {}
28+
struct ImpliedOther: ImplierOther {}

test/Sema/enum_conformance_synthesis.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,18 @@ extension UnusedGenericDeriveExtension: Hashable {}
314314
extension GenericOtherFileNonconforming: Equatable where T: Equatable {}
315315
// expected-error@-1{{implementation of 'Equatable' cannot be automatically synthesized in an extension in a different file to the type}}
316316

317+
// rdar://problem/41852654
318+
319+
// There is a conformance to Equatable (or at least, one that implies Equatable)
320+
// in the same file as the type, so the synthesis is okay. Both orderings are
321+
// tested, to catch choosing extensions based on the order of the files, etc.
322+
protocol ImplierMain: Equatable {}
323+
enum ImpliedMain: ImplierMain {
324+
case a(Int)
325+
}
326+
extension ImpliedOther: ImplierMain {}
327+
328+
317329
// FIXME: Remove -verify-ignore-unknown.
318330
// <unknown>:0: error: unexpected error produced: invalid redeclaration of 'hashValue'
319331
// <unknown>:0: error: unexpected note produced: candidate has non-matching type '(Foo, Foo) -> Bool'

test/Sema/struct_equatable_hashable.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,15 @@ extension UnusedGenericDeriveExtension: Hashable {}
253253
extension GenericOtherFileNonconforming: Equatable where T: Equatable {}
254254
// expected-error@-1{{implementation of 'Equatable' cannot be automatically synthesized in an extension in a different file to the type}}
255255

256+
// rdar://problem/41852654
257+
258+
// There is a conformance to Equatable (or at least, one that implies Equatable)
259+
// in the same file as the type, so the synthesis is okay. Both orderings are
260+
// tested, to catch choosing extensions based on the order of the files, etc.
261+
protocol ImplierMain: Equatable {}
262+
struct ImpliedMain: ImplierMain {}
263+
extension ImpliedOther: ImplierMain {}
264+
256265
// FIXME: Remove -verify-ignore-unknown.
257266
// <unknown>:0: error: unexpected error produced: invalid redeclaration of 'hashValue'
258267
// <unknown>:0: error: unexpected note produced: candidate has non-matching type '(Foo, Foo) -> Bool'

0 commit comments

Comments
 (0)