Skip to content

Commit 34650e8

Browse files
authored
Merge pull request #32799 from AnthonyLatsis/sself-is-fixed
AssociatedTypeInference: Allow Self as a fixed type witness
2 parents d3f0de8 + 2853114 commit 34650e8

File tree

5 files changed

+125
-24
lines changed

5 files changed

+125
-24
lines changed

include/swift/AST/GenericSignatureBuilder.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -751,7 +751,7 @@ class GenericSignatureBuilder {
751751
/// \param resolutionKind How to perform the resolution.
752752
///
753753
/// \param wantExactPotentialArchetype Whether to return the precise
754-
/// potential archetype described by the type (vs. just the equivalance
754+
/// potential archetype described by the type (vs. just the equivalence
755755
/// class and resolved type).
756756
ResolvedType maybeResolveEquivalenceClass(
757757
Type type,

lib/AST/GenericSignatureBuilder.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6218,7 +6218,7 @@ static bool removalDisconnectsEquivalenceClass(
62186218
// derived edges).
62196219
if (fromComponentIndex == toComponentIndex) return false;
62206220

6221-
/// Describes the parents in the equivalance classes we're forming.
6221+
/// Describes the parents in the equivalence classes we're forming.
62226222
SmallVector<unsigned, 4> parents;
62236223
for (unsigned i : range(equivClass->derivedSameTypeComponents.size())) {
62246224
parents.push_back(i);

lib/Sema/TypeCheckProtocolInference.cpp

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -805,25 +805,30 @@ Type AssociatedTypeInference::computeFixedTypeWitness(
805805
AssociatedTypeDecl *assocType) {
806806
// Look at all of the inherited protocols to determine whether they
807807
// require a fixed type for this associated type.
808-
Type dependentType = assocType->getDeclaredInterfaceType();
809808
Type resultType;
810809
for (auto conformedProto : adoptee->getAnyNominal()->getAllProtocols()) {
811810
if (!conformedProto->inheritsFrom(assocType->getProtocol()))
812811
continue;
813812

814-
auto genericSig = conformedProto->getGenericSignature();
813+
const auto genericSig = conformedProto->getGenericSignature();
815814
if (!genericSig) return Type();
816815

817-
Type concreteType = genericSig->getConcreteType(dependentType);
818-
if (!concreteType) continue;
816+
const auto nestedType = genericSig->getCanonicalTypeInContext(
817+
DependentMemberType::get(conformedProto->getSelfInterfaceType(),
818+
assocType->getName()));
819+
if (nestedType->isEqual(conformedProto->getSelfInterfaceType())) {
820+
// Self is a valid fixed type witness.
821+
} else if (nestedType->isTypeParameter()) {
822+
continue;
823+
}
819824

820825
if (!resultType) {
821-
resultType = concreteType;
826+
resultType = nestedType;
822827
continue;
823828
}
824829

825830
// FIXME: Bailing out on ambiguity.
826-
if (!resultType->isEqual(concreteType))
831+
if (!resultType->isEqual(nestedType))
827832
return Type();
828833
}
829834

@@ -887,7 +892,7 @@ AssociatedTypeInference::computeAbstractTypeWitness(
887892
return AbstractTypeWitness::forFixed(assocType, concreteType);
888893

889894
// If we can form a default type, do so.
890-
if (auto typeWitness = computeDefaultTypeWitness(assocType))
895+
if (const auto &typeWitness = computeDefaultTypeWitness(assocType))
891896
return typeWitness;
892897

893898
// If there is a generic parameter of the named type, use that.

test/decl/protocol/req/associated_type_inference.swift

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -676,21 +676,12 @@ struct S40<E: Equatable>: P40c {
676676
typealias B = Self
677677
}
678678

679-
// Self is not treated as a fixed type witness.
679+
// Fails to find the fixed type witness B == FIXME_S1<A>.
680680
protocol FIXME_P1a {
681-
associatedtype A // expected-note {{protocol requires nested type 'A'}}
682-
}
683-
protocol FIXME_P1b: FIXME_P1a where A == Self {}
684-
// expected-error@+2 {{type 'FIXME_S1' does not conform to protocol 'FIXME_P1a'}}
685-
// expected-error@+1 {{type 'FIXME_S1' does not conform to protocol 'FIXME_P1b'}}
686-
struct FIXME_S1: FIXME_P1b {}
687-
688-
// Fails to find the fixed type witness B == FIXME_S2<A>.
689-
protocol FIXME_P2a {
690681
associatedtype A: Equatable = Never // expected-note {{protocol requires nested type 'A'}}
691-
associatedtype B: FIXME_P2a // expected-note {{protocol requires nested type 'B'}}
682+
associatedtype B: FIXME_P1a // expected-note {{protocol requires nested type 'B'}}
692683
}
693-
protocol FIXME_P2b: FIXME_P2a where B == FIXME_S2<A> {}
694-
// expected-error@+2 {{type 'FIXME_S2<T>' does not conform to protocol 'FIXME_P2a'}}
695-
// expected-error@+1 {{type 'FIXME_S2<T>' does not conform to protocol 'FIXME_P2b'}}
696-
struct FIXME_S2<T: Equatable>: FIXME_P2b {}
684+
protocol FIXME_P1b: FIXME_P1a where B == FIXME_S1<A> {}
685+
// expected-error@+2 {{type 'FIXME_S1<T>' does not conform to protocol 'FIXME_P1a'}}
686+
// expected-error@+1 {{type 'FIXME_S1<T>' does not conform to protocol 'FIXME_P1b'}}
687+
struct FIXME_S1<T: Equatable>: FIXME_P1b {}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
// RUN: %target-typecheck-verify-swift
2+
3+
protocol P1 where A == Never {
4+
associatedtype A // expected-note {{protocol requires nested type 'A'}}
5+
}
6+
// FIXME: Should this infer A := Never?
7+
struct S1: P1 {} // expected-error {{type 'S1' does not conform to protocol 'P1'}}
8+
9+
protocol P2a {
10+
associatedtype A
11+
}
12+
protocol P2b: P2a where A == Never {}
13+
protocol P2c: P2b {}
14+
struct S2a: P2b {} // OK, A := Never
15+
struct S2b: P2c {} // OK, A := Never
16+
17+
// Fixed type witnesses can reference dependent members.
18+
protocol P3a {
19+
associatedtype A
20+
associatedtype B
21+
}
22+
protocol P3b: P3a where A == [B] {}
23+
struct S3: P3b { // OK, A := [Never], B := Never
24+
typealias B = Never
25+
}
26+
27+
protocol P4 {}
28+
extension P4 {
29+
typealias B = Self
30+
}
31+
struct S4: P4, P3b {} // OK, A := [S4], B := S4
32+
33+
// Self is a valid fixed type witness.
34+
protocol P5a {
35+
associatedtype A
36+
}
37+
protocol P5b: P5a where A == Self {}
38+
struct S5<X>: P5b {} // OK, A := S5<X>
39+
40+
41+
protocol P6 where A == Never { // expected-error {{same-type constraint type 'Never' does not conform to required protocol 'P6'}}
42+
// expected-error@+2 {{same-type constraint type 'Never' does not conform to required protocol 'P6'}}
43+
// expected-note@+1 {{protocol requires nested type 'A}}
44+
associatedtype A: P6
45+
}
46+
struct S6: P6 {} // expected-error {{type 'S6' does not conform to protocol 'P6'}}
47+
48+
protocol P7a where A == Never {
49+
associatedtype A
50+
}
51+
// expected-error@+2 {{'Self.A' cannot be equal to both 'Bool' and 'Never'}}
52+
// expected-note@+1 {{same-type constraint 'Self.A' == 'Never' implied here}}
53+
protocol P7b: P7a where A == Bool {}
54+
struct S7: P7b {}
55+
56+
protocol P8 where A == Bool {
57+
associatedtype A // expected-note {{protocol requires nested type 'A'}}
58+
}
59+
// expected-error@+2 {{type 'S8' does not conform to protocol 'P7a'}}
60+
// expected-error@+1 {{type 'S8' does not conform to protocol 'P8'}}
61+
struct S8: P8, P7a {}
62+
63+
protocol P9a where A == Never {
64+
associatedtype A
65+
}
66+
protocol P9b: P9a {
67+
associatedtype A // expected-note {{protocol requires nested type 'A'}}
68+
}
69+
// FIXME: Associated type restatement sabotages the conformance.
70+
// expected-error@+2 {{type 'S9a' does not conform to protocol 'P9a'}}
71+
// expected-error@+1 {{type 'S9a' does not conform to protocol 'P9b'}}
72+
struct S9a: P9b {}
73+
// expected-error@+2 {{'P9a' requires the types 'S9b.A' (aka 'Bool') and 'Never' be equivalent}}
74+
// expected-note@+1 {{requirement specified as 'Self.A' == 'Never' [with Self = S9b]}}
75+
struct S9b: P9b {
76+
typealias A = Bool
77+
}
78+
struct S9c: P9b { // OK, S9c.A does not contradict Self.A == Never.
79+
typealias Sugar = Never
80+
typealias A = Sugar
81+
}
82+
83+
protocol P10 {}
84+
extension P10 {
85+
typealias A = Bool
86+
}
87+
// FIXME: 'P10 extension.A' should not be considered a viable type witness;
88+
// instead, the compiler should infer A := Never and synthesize S10.A.
89+
// expected-error@+2 {{'P9a' requires the types 'S10.A' (aka 'Bool') and 'Never' be equivalent}}
90+
// expected-note@+1 {{requirement specified as 'Self.A' == 'Never' [with Self = S10]}}
91+
struct S10: P10, P9a {}
92+
93+
protocol P11a {
94+
associatedtype A
95+
}
96+
protocol P11b: P11a where A == Never {}
97+
protocol Q11 {
98+
associatedtype A // expected-note {{protocol requires nested type 'A'}}
99+
}
100+
// FIXME: Unrelated protocols with a matching associated type should
101+
// also be considered when computing a fixed type witness.
102+
// expected-error@+3 {{type 'S11' does not conform to protocol 'Q11'}}
103+
// expected-error@+2 {{type 'S11' does not conform to protocol 'P11a'}}
104+
// expected-error@+1 {{type 'S11' does not conform to protocol 'P11b'}}
105+
struct S11: Q11, P11b {}

0 commit comments

Comments
 (0)