Skip to content

Commit 23ef893

Browse files
committed
Sema: New strategy for dealing with completely fixed associated types
If a protocol fixes an associated type of another protocol via a concrete same-type requirement, we should make use of this fact immediately when building the associated type inference constraint system. Previously we only introduced fixed type bindings at the end, and only in the 'abstract type witness' inference path, which we reach if a type witness cannot be resolved by looking at value witnesses alone. This meant that associated type inference would find valid or ambiguous solutions which would then be contradicted by the ensureRequirementsAreSatisfied() check. Longer term, what I want to do is actually build the type witness system upfront, and also teach the constraint solver here about merging equivalence classes, so that we can split them again when backtracking. This will combine the best of both approaches. Fixes rdar://problem/122586992.
1 parent 0f1234d commit 23ef893

File tree

3 files changed

+77
-44
lines changed

3 files changed

+77
-44
lines changed

lib/Sema/AssociatedTypeInference.cpp

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1830,6 +1830,32 @@ InferredAssociatedTypesByWitnesses
18301830
AssociatedTypeInference::inferTypeWitnessesViaAssociatedType(
18311831
const llvm::SetVector<AssociatedTypeDecl *> &allUnresolved,
18321832
AssociatedTypeDecl *assocType) {
1833+
InferredAssociatedTypesByWitnesses result;
1834+
1835+
// Check if this associated type is actually fixed to a fully concrete type by
1836+
// a same-type requirement in a protocol that our conforming type conforms to.
1837+
//
1838+
// A more general form of this analysis that also handles same-type
1839+
// requirements between type parameters is performed later in
1840+
// inferAbstractTypeWitnesses().
1841+
//
1842+
// We handle the fully concrete case here, which completely rules out
1843+
// certain invalid solutions.
1844+
if (ctx.LangOpts.EnableExperimentalAssociatedTypeInference) {
1845+
if (auto fixedType = computeFixedTypeWitness(assocType)) {
1846+
if (!fixedType->hasTypeParameter()) {
1847+
InferredAssociatedTypesByWitness inferred;
1848+
inferred.Witness = assocType;
1849+
inferred.Inferred.push_back({assocType, fixedType});
1850+
result.push_back(std::move(inferred));
1851+
1852+
// That's it; we're forced into this binding, so we're not adding another
1853+
// tautology below.
1854+
return result;
1855+
}
1856+
}
1857+
}
1858+
18331859
// Form the default name _Default_Foo.
18341860
DeclNameRef defaultName;
18351861
{
@@ -1856,8 +1882,6 @@ AssociatedTypeInference::inferTypeWitnessesViaAssociatedType(
18561882
: cast<NominalTypeDecl>(dc)->getStartLoc(),
18571883
subOptions, lookupResults);
18581884

1859-
InferredAssociatedTypesByWitnesses result;
1860-
18611885
for (auto decl : lookupResults) {
18621886
// We want type declarations.
18631887
auto typeDecl = dyn_cast<TypeDecl>(decl);

test/decl/protocol/req/associated_type_inference_fixed_type_experimental_inference.swift

Lines changed: 13 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,16 @@
44
protocol P1 where A == Never {
55
associatedtype A
66
}
7-
// CHECK-LABEL: Abstract type witness system for conformance of S1 to P1: {
8-
// CHECK-NEXT: A => Never (preferred),
9-
// CHECK-NEXT: }
7+
108
struct S1: P1 {}
119

1210
protocol P2a {
1311
associatedtype A
1412
}
1513
protocol P2b: P2a where A == Never {}
1614
protocol P2c: P2b {}
17-
// CHECK-LABEL: Abstract type witness system for conformance of S2a to P2a: {
18-
// CHECK-NEXT: A => Never,
19-
// CHECK-NEXT: }
15+
2016
struct S2a: P2b {}
21-
// CHECK-LABEL: Abstract type witness system for conformance of S2b to P2a: {
22-
// CHECK-NEXT: A => Never,
23-
// CHECK-NEXT: }
2417
struct S2b: P2c {}
2518

2619
// Fixed type witnesses can reference dependent members.
@@ -74,9 +67,6 @@ protocol P7a where A == Never {
7467
}
7568
// expected-error@+1 {{no type for 'Self.A' can satisfy both 'Self.A == Never' and 'Self.A == Bool'}}
7669
protocol P7b: P7a where A == Bool {}
77-
// CHECK-LABEL: Abstract type witness system for conformance of S7 to P7a: {
78-
// CHECK-NEXT: A => Never (preferred),
79-
// CHECK-NEXT: }
8070
struct S7: P7b {}
8171

8272
protocol P8a where A == Never {
@@ -100,9 +90,7 @@ protocol P9a where A == Never {
10090
protocol P9b: P9a {
10191
associatedtype A
10292
}
103-
// CHECK-LABEL: Abstract type witness system for conformance of S9a to P9b: {
104-
// CHECK-NEXT: A => Never,
105-
// CHECK-NEXT: }
93+
10694
struct S9a: P9b {}
10795
// expected-error@+2 {{type 'S9b' does not conform to protocol 'P9a'}}
10896
// expected-error@+1 {{'P9a' requires the types 'S9b.A' (aka 'Bool') and 'Never' be equivalent}}
@@ -136,9 +124,6 @@ protocol Q11 {
136124
associatedtype A
137125
}
138126
do {
139-
// CHECK-LABEL: Abstract type witness system for conformance of Conformer to Q11: {
140-
// CHECK-NEXT: A => Never,
141-
// CHECK-NEXT: }
142127
struct Conformer: Q11, P11b {}
143128
}
144129

@@ -225,7 +210,6 @@ protocol P17d {
225210
}
226211
do {
227212
// CHECK-LABEL: Abstract type witness system for conformance of Conformer1 to P17a: {
228-
// CHECK-NEXT: A => Never (preferred),
229213
// CHECK-NEXT: B => (unresolved){{$}}
230214
// CHECK-NEXT: }
231215
struct Conformer1: P17a {} // expected-error {{type 'Conformer1' does not conform to protocol 'P17a'}}
@@ -235,8 +219,7 @@ do {
235219
// CHECK-NEXT: }
236220
struct Conformer2<A>: P17b {} // expected-error {{type 'Conformer2<A>' does not conform to protocol 'P17b'}}
237221
// CHECK-LABEL: Abstract type witness system for conformance of Conformer3 to P17c: {
238-
// CHECK-NEXT: A => Never (preferred), [[EQUIV_CLASS:0x[0-9a-f]+]]
239-
// CHECK-NEXT: B => Never (preferred), [[EQUIV_CLASS]]
222+
// CHECK-NEXT: B => Self.A (preferred), [[EQUIV_CLASS:0x[0-9a-f]+]]
240223
// CHECK-NEXT: }
241224
struct Conformer3: P17c {}
242225
// CHECK-LABEL: Abstract type witness system for conformance of Conformer4<A> to P17d: {
@@ -371,14 +354,12 @@ protocol P25c_1: P25a_1, P25b {}
371354
protocol P25c_2: P25a_2, P25b {}
372355
do {
373356
// CHECK-LABEL: Abstract type witness system for conformance of Conformer1<C> to P25a_1: {
374-
// CHECK-NEXT: A => Int (preferred), [[EQUIV_CLASS:0x[0-9a-f]+]]
375-
// CHECK-NEXT: B => Int (preferred), [[EQUIV_CLASS]]
357+
// CHECK-NEXT: B => Self.C.Element (preferred), [[EQUIV_CLASS:0x[0-9a-f]+]]
376358
// CHECK-NEXT: C => C (preferred),
377359
// CHECK-NEXT: }
378360
struct Conformer1<C: Sequence>: P25c_1 where C.Element == Int {}
379361
// CHECK-LABEL: Abstract type witness system for conformance of Conformer2<C> to P25a_2: {
380-
// CHECK-NEXT: A => Int (preferred), [[EQUIV_CLASS:0x[0-9a-f]+]]
381-
// CHECK-NEXT: B => Int (preferred), [[EQUIV_CLASS]]
362+
// CHECK-NEXT: B => Int (preferred), [[EQUIV_CLASS:0x[0-9a-f]+]]
382363
// CHECK-NEXT: C => C (preferred),
383364
// CHECK-NEXT: }
384365
struct Conformer2<C: Sequence>: P25c_2 where C.Element == Int {}
@@ -418,15 +399,11 @@ protocol P27b where A == B.Element {
418399
protocol P27c_1: P27a, P27b {}
419400
protocol P27c_2: P27b, P27a {}
420401
do {
421-
// CHECK-LABEL: Abstract type witness system for conformance of Conformer1<B> to P27a: {
422-
// CHECK-NEXT: A => Int (preferred),
423-
// CHECK-NEXT: }
424402
// CHECK-LABEL: Abstract type witness system for conformance of Conformer1<B> to P27b: {
425403
// CHECK-NEXT: B => B (preferred),
426404
// CHECK-NEXT: }
427405
struct Conformer1<B: Sequence>: P27c_1 where B.Element == Int {}
428406
// CHECK-LABEL: Abstract type witness system for conformance of Conformer2<B> to P27b: {
429-
// CHECK-NEXT: A => Int (preferred),
430407
// CHECK-NEXT: B => B (preferred),
431408
// CHECK-NEXT: }
432409
struct Conformer2<B: Sequence>: P27c_2 where B.Element == Int {}
@@ -465,8 +442,8 @@ do {
465442
}
466443

467444
protocol P29a where A == Int {
468-
associatedtype A // expected-note {{protocol requires nested type 'A'; add nested type 'A' for conformance}}
469-
associatedtype B // expected-note {{protocol requires nested type 'B'; add nested type 'B' for conformance}}
445+
associatedtype A
446+
associatedtype B
470447
}
471448
protocol P29b where B == Never {
472449
associatedtype B
@@ -481,17 +458,15 @@ protocol Q29b: P29c, P29a, P29b {}
481458
// expected-error@-1 {{no type for 'Self.A' can satisfy both 'Self.A == Never' and 'Self.A == Int'}}
482459
do {
483460
// CHECK-LABEL: Abstract type witness system for conformance of Conformer1 to P29a: {
484-
// CHECK-NEXT: A => (ambiguous), [[EQUIV_CLASS:0x[0-9a-f]+]]
485-
// CHECK-NEXT: B => (ambiguous), [[EQUIV_CLASS]]
461+
// CHECK-NEXT: B => Never, [[EQUIV_CLASS:0x[0-9a-f]+]]
486462
// CHECK-NEXT: }
487463
struct Conformer1: Q29a {}
488-
// expected-error@-1 {{type 'Conformer1' does not conform to protocol 'P29a'}}
489-
// expected-error@-2 {{type 'Conformer1' does not conform to protocol 'P29b'}}
464+
// expected-note@-1 {{requirement specified as 'Self.A' == 'Self.B' [with Self = Conformer1]}}
465+
// expected-error@-2 {{'P29c' requires the types 'Conformer1.A' (aka 'Int') and 'Conformer1.B' (aka 'Never') be equivalent}}
490466
// expected-error@-3 {{type 'Conformer1' does not conform to protocol 'P29c'}}
491467

492468
// CHECK-LABEL: Abstract type witness system for conformance of Conformer2 to P29c: {
493-
// CHECK-NEXT: A => (ambiguous), [[EQUIV_CLASS:0x[0-9a-f]+]]
494-
// CHECK-NEXT: B => (ambiguous), [[EQUIV_CLASS]]
469+
// CHECK-NEXT: B => Never (preferred), [[EQUIV_CLASS:0x[0-9a-f]+]]
495470
// CHECK-NEXT: }
496471
struct Conformer2: Q29b {}
497472
// expected-error@-1 {{type 'Conformer2' does not conform to protocol 'P29a'}}
@@ -536,8 +511,7 @@ protocol Q31: P31c, P31a, P31b {}
536511
// expected-error@-1 {{no type for 'Self.A' can satisfy both 'Self.A == Never' and 'Self.A == Int'}}
537512
do {
538513
// CHECK-LABEL: Abstract type witness system for conformance of Conformer to P31c: {
539-
// CHECK-NEXT: A => (ambiguous), [[EQUIV_CLASS:0x[0-9a-f]+]]
540-
// CHECK-NEXT: B => (ambiguous), [[EQUIV_CLASS]]
514+
// CHECK-NEXT: B => (ambiguous), [[EQUIV_CLASS:0x[0-9a-f]+]]
541515
// CHECK-NEXT: }
542516
struct Conformer: Q31 {}
543517
// expected-error@-1 {{type 'Conformer' does not conform to protocol 'P31a'}}
@@ -589,9 +563,6 @@ protocol P33b where A == Int {
589563
}
590564
protocol Q33: P33a, P33b {}
591565
do {
592-
// CHECK-LABEL: Abstract type witness system for conformance of Conformer to P33a: {
593-
// CHECK-NEXT: A => Int (preferred),
594-
// CHECK-NEXT: }
595566
struct Conformer: Q33 {}
596567
}
597568

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// RUN: %target-typecheck-verify-swift -enable-experimental-associated-type-inference
2+
// RUN: %target-typecheck-verify-swift -disable-experimental-associated-type-inference
3+
4+
public protocol P1 {
5+
associatedtype A
6+
func f() -> A
7+
}
8+
9+
public struct S1 {}
10+
11+
extension Int: P1 {
12+
public func f() -> S1 { fatalError() }
13+
}
14+
15+
public protocol P2: RawRepresentable, P1 {}
16+
17+
public struct S2 {}
18+
19+
extension P2 where RawValue == S2, A == S2 {
20+
// This is not a candidate witness, because we require A == S1.
21+
public func f() -> A { fatalError() }
22+
}
23+
24+
extension P2 where RawValue: P1, RawValue.A == A {
25+
// This is a candidate witness.
26+
public func f() -> A { fatalError() }
27+
}
28+
29+
public protocol P3: P2 where A == S1, RawValue == Int {}
30+
31+
// When checking [S3: P1], the fact that P3 has [A == S1] should completely
32+
// solve everything.
33+
public struct S3: P3 {
34+
public init(rawValue: Int) { fatalError() }
35+
public var rawValue: Int { fatalError() }
36+
}
37+
38+
let x: S1.Type = S3.A.self

0 commit comments

Comments
 (0)