Skip to content

Commit b18c7fb

Browse files
committed
Sema: Allow re-declarations of typealiases in constrained extensions with different generic signatures
Associated type inference will synthesize typealiases in constrained extensions for conditional conformances, but then we might later flag them as re-declarations. Let's not do this, since name lookup does check if generic requirements are satisfied, so such redeclarations are not in fact erroneous. Fixes <rdar://problem/68933045>.
1 parent 727baf1 commit b18c7fb

File tree

3 files changed

+61
-5
lines changed

3 files changed

+61
-5
lines changed

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -565,20 +565,22 @@ CheckRedeclarationRequest::evaluate(Evaluator &eval, ValueDecl *current) const {
565565
if (current == other || (other->hasInterfaceType() && other->isInvalid()))
566566
continue;
567567

568+
auto *otherDC = other->getDeclContext();
569+
568570
// Skip declarations in other modules.
569-
if (currentModule != other->getModuleContext())
571+
if (currentModule != otherDC->getParentModule())
570572
continue;
571573

572574
// If both declarations are in the same file, only diagnose the second one.
573-
if (currentFile == other->getDeclContext()->getParentSourceFile())
575+
if (currentFile == otherDC->getParentSourceFile())
574576
if (current->getLoc().isValid() &&
575577
ctx.SourceMgr.isBeforeInBuffer(
576578
current->getLoc(), other->getLoc()))
577579
continue;
578580

579581
// Don't compare methods vs. non-methods (which only happens with
580582
// operators).
581-
if (currentDC->isTypeContext() != other->getDeclContext()->isTypeContext())
583+
if (currentDC->isTypeContext() != otherDC->isTypeContext())
582584
continue;
583585

584586
// In local context, only consider exact name matches.
@@ -592,7 +594,7 @@ CheckRedeclarationRequest::evaluate(Evaluator &eval, ValueDecl *current) const {
592594
if (!conflicting(currentSig, otherSig))
593595
continue;
594596

595-
// Skip declarations in other files.
597+
// Skip inaccessible declarations in other files.
596598
// In practice, this means we will warn on a private declaration that
597599
// shadows a non-private one, but only in the file where the shadowing
598600
// happens. We will warn on conflicting non-private declarations in both
@@ -605,6 +607,15 @@ CheckRedeclarationRequest::evaluate(Evaluator &eval, ValueDecl *current) const {
605607
if (other->isInvalid())
606608
continue;
607609

610+
// Allow redeclarations of typealiases in different constrained
611+
// extensions.
612+
if (isa<TypeAliasDecl>(current) &&
613+
isa<TypeAliasDecl>(other) &&
614+
currentDC != otherDC &&
615+
currentDC->getGenericSignatureOfContext().getCanonicalSignature() !=
616+
otherDC->getGenericSignatureOfContext().getCanonicalSignature())
617+
continue;
618+
608619
// Thwart attempts to override the same declaration more than once.
609620
const auto *currentOverride = current->getOverriddenDecl();
610621
const auto *otherOverride = other->getOverriddenDecl();

test/decl/protocol/req/missing_conformance.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ extension CountSteps1 // expected-error {{type 'CountSteps1<T>' does not conform
132132
where T : Equatable
133133
{
134134
typealias Index = Int
135-
// expected-error@-1 {{invalid redeclaration of synthesized implementation for protocol requirement 'Index'}}
135+
136136
func index(_ i: Index, offsetBy d: Int) -> Index {
137137
return i + d
138138
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// RUN: %target-typecheck-verify-swift
2+
3+
struct NonGenericStruct {
4+
typealias Horse = Int // expected-note {{'Horse' previously declared here}}
5+
typealias Horse = String // expected-error {{invalid redeclaration of 'Horse'}}
6+
}
7+
8+
struct NonGenericExtendedStruct {}
9+
10+
extension NonGenericExtendedStruct {
11+
typealias Horse = Int // expected-note {{'Horse' previously declared here}}
12+
}
13+
14+
extension NonGenericExtendedStruct {
15+
typealias Horse = String // expected-error {{invalid redeclaration of 'Horse'}}
16+
}
17+
18+
struct GenericStruct<T> {
19+
typealias Horse = Int // expected-note {{'Horse' previously declared here}}
20+
typealias Horse = String // expected-error {{invalid redeclaration of 'Horse'}}
21+
}
22+
23+
struct GenericExtendedStruct<T> {}
24+
25+
extension GenericExtendedStruct {
26+
typealias Horse = Int // expected-note {{'Horse' previously declared here}}
27+
}
28+
29+
extension GenericExtendedStruct {
30+
typealias Horse = String // expected-error {{invalid redeclaration of 'Horse'}}
31+
}
32+
33+
struct GenericConstrainedExtendedStruct<T> {}
34+
35+
protocol SomeProtocol {}
36+
37+
extension GenericConstrainedExtendedStruct where T : SomeProtocol {
38+
typealias Horse = Int
39+
}
40+
41+
protocol OtherProtocol {}
42+
43+
extension GenericConstrainedExtendedStruct where T : OtherProtocol {
44+
typealias Horse = String // This is OK!
45+
}

0 commit comments

Comments
 (0)