Skip to content

Commit cdf1da8

Browse files
authored
Merge pull request #71773 from slavapestov/fix-rdar123345520
Sema: Two associated type inference fixes
2 parents aab7c89 + ba90861 commit cdf1da8

10 files changed

+213
-33
lines changed

lib/Sema/AssociatedTypeInference.cpp

Lines changed: 39 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1017,6 +1017,10 @@ class AssociatedTypeInference {
10171017
std::pair<Type, TypeDecl *>
10181018
computeDerivedTypeWitness(AssociatedTypeDecl *assocType);
10191019

1020+
/// See if we have a generic parameter named the same as this associated
1021+
/// type.
1022+
Type computeGenericParamWitness(AssociatedTypeDecl *assocType) const;
1023+
10201024
/// Compute a type witness without using a specific potential witness.
10211025
llvm::Optional<AbstractTypeWitness>
10221026
computeAbstractTypeWitness(AssociatedTypeDecl *assocType);
@@ -2389,6 +2393,7 @@ Type AssociatedTypeInference::computeFixedTypeWitness(
23892393
// any fix this associated type to a concrete type.
23902394
for (auto conformance : getPeerConformances(conformance)) {
23912395
auto *conformedProto = conformance->getProtocol();
2396+
23922397
auto sig = conformedProto->getGenericSignature();
23932398

23942399
// FIXME: The RequirementMachine will assert on re-entrant construction.
@@ -2656,6 +2661,28 @@ AssociatedTypeInference::computeAbstractTypeWitness(
26562661
return llvm::None;
26572662
}
26582663

2664+
/// Look for a generic parameter that matches the name of the
2665+
/// associated type.
2666+
Type AssociatedTypeInference::computeGenericParamWitness(
2667+
AssociatedTypeDecl *assocType) const {
2668+
if (auto genericSig = dc->getGenericSignatureOfContext()) {
2669+
// Ignore the generic parameters for AsyncIteratorProtocol.Failure and
2670+
// AsyncSequence.Failure.
2671+
if (!isAsyncIteratorProtocolFailure(assocType)) {
2672+
for (auto *gp : genericSig.getInnermostGenericParams()) {
2673+
// Packs cannot witness associated type requirements.
2674+
if (gp->isParameterPack())
2675+
continue;
2676+
2677+
if (gp->getName() == assocType->getName())
2678+
return dc->mapTypeIntoContext(gp);
2679+
}
2680+
}
2681+
}
2682+
2683+
return Type();
2684+
}
2685+
26592686
void AssociatedTypeInference::collectAbstractTypeWitnesses(
26602687
TypeWitnessSystem &system,
26612688
ArrayRef<AssociatedTypeDecl *> unresolvedAssocTypes) const {
@@ -2704,35 +2731,15 @@ void AssociatedTypeInference::collectAbstractTypeWitnesses(
27042731
if (system.hasResolvedTypeWitness(assocType->getName()))
27052732
continue;
27062733

2707-
// If we find a default type definition, feed it to the system.
2708-
if (const auto &typeWitness = computeDefaultTypeWitness(assocType)) {
2734+
if (auto gpType = computeGenericParamWitness(assocType)) {
2735+
system.addTypeWitness(assocType->getName(), gpType, /*preferred=*/true);
2736+
} else if (const auto &typeWitness = computeDefaultTypeWitness(assocType)) {
27092737
bool preferred = (typeWitness->getDefaultedAssocType()->getDeclContext()
27102738
== conformance->getProtocol());
27112739
system.addDefaultTypeWitness(typeWitness->getType(),
27122740
typeWitness->getDefaultedAssocType(),
27132741
preferred);
2714-
} else {
2715-
// As a last resort, look for a generic parameter that matches the name
2716-
// of the associated type.
2717-
if (auto genericSig = dc->getGenericSignatureOfContext()) {
2718-
// Ignore the generic parameters for AsyncIteratorProtocol.Failure and
2719-
// AsyncSequence.Failure.
2720-
if (!isAsyncIteratorProtocolFailure(assocType)) {
2721-
for (auto *gp : genericSig.getInnermostGenericParams()) {
2722-
// Packs cannot witness associated type requirements.
2723-
if (gp->isParameterPack())
2724-
continue;
2725-
2726-
if (gp->getName() == assocType->getName()) {
2727-
system.addTypeWitness(assocType->getName(),
2728-
dc->mapTypeIntoContext(gp),
2729-
/*preferred=*/true);
2730-
}
2731-
}
2732-
}
2733-
}
27342742
}
2735-
27362743
}
27372744
}
27382745

@@ -3150,8 +3157,15 @@ AssociatedTypeDecl *AssociatedTypeInference::inferAbstractTypeWitnesses(
31503157

31513158
// If simplification failed, give up.
31523159
if (type->hasTypeParameter()) {
3153-
LLVM_DEBUG(llvm::dbgs() << "-- Simplification failed: " << type << "\n");
3154-
return assocType;
3160+
if (auto gpType = computeGenericParamWitness(assocType)) {
3161+
LLVM_DEBUG(llvm::dbgs() << "-- Found generic parameter as last resort: "
3162+
<< gpType << "\n");
3163+
type = gpType;
3164+
typeWitnesses.insert(assocType, {type, reqDepth});
3165+
} else {
3166+
LLVM_DEBUG(llvm::dbgs() << "-- Simplification failed: " << type << "\n");
3167+
return assocType;
3168+
}
31553169
}
31563170

31573171
if (const auto failed =
Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
// RUN: %target-typecheck-verify-swift -enable-experimental-associated-type-inference
2-
// RUN: %target-typecheck-verify-swift -disable-experimental-associated-type-inference
2+
// RUN: not %target-typecheck-verify-swift -disable-experimental-associated-type-inference
33

44
protocol P {
55
associatedtype A = Int
66
}
77

88
struct S<A>: P {}
99

10-
// This is unfortunate but it is the behavior of Swift 5.10.
11-
let x: Int.Type = S<String>.A.self
10+
let x: String.Type = S<String>.A.self

test/decl/protocol/req/associated_type_inference_fixed_type_experimental_inference.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ do {
212212
// CHECK-NEXT: }
213213
struct Conformer1: P17a {} // expected-error {{type 'Conformer1' does not conform to protocol 'P17a'}}
214214
// CHECK-LABEL: Abstract type witness system for conformance of Conformer2<A> to P17b: {
215-
// CHECK-NEXT: A => (unresolved), [[EQUIV_CLASS:0x[0-9a-f]+]]
215+
// CHECK-NEXT: A => A (preferred), [[EQUIV_CLASS:0x[0-9a-f]+]]
216216
// CHECK-NEXT: B => (unresolved)
217217
// CHECK-NEXT: }
218218
struct Conformer2<A>: P17b {} // expected-error {{type 'Conformer2<A>' does not conform to protocol 'P17b'}}
@@ -221,7 +221,7 @@ do {
221221
// CHECK-NEXT: }
222222
struct Conformer3: P17c {}
223223
// CHECK-LABEL: Abstract type witness system for conformance of Conformer4<A> to P17d: {
224-
// CHECK-NEXT: A => Int (preferred), [[EQUIV_CLASS:0x[0-9a-f]+]]
224+
// CHECK-NEXT: A => A (preferred), [[EQUIV_CLASS:0x[0-9a-f]+]]
225225
// CHECK-NEXT: B => Int (preferred), [[EQUIV_CLASS:0x[0-9a-f]+]]
226226
// CHECK-NEXT: }
227227
struct Conformer4<A>: P17d {}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// RUN: %target-typecheck-verify-swift -enable-experimental-associated-type-inference
2+
// RUN: %target-typecheck-verify-swift -disable-experimental-associated-type-inference
3+
4+
// REQUIRES: objc_interop
5+
6+
import Foundation
7+
8+
public struct CustomCollection<T>: RandomAccessCollection {
9+
public typealias Indices = Range<Int>
10+
11+
public var startIndex: Int { fatalError() }
12+
public var endIndex: Int { fatalError() }
13+
public var count: Int { fatalError() }
14+
15+
public subscript(position: Int) -> T {
16+
get { fatalError() }
17+
set { fatalError() }
18+
}
19+
20+
public var underestimatedCount: Int { fatalError() }
21+
}
22+
23+
extension CustomCollection: ContiguousBytes where Element == UInt8 {
24+
public func withUnsafeBytes<R>(_ body: (UnsafeRawBufferPointer) throws -> R) rethrows -> R {
25+
fatalError()
26+
}
27+
}
28+
29+
extension CustomCollection: DataProtocol where Element == UInt8 {
30+
public var regions: CollectionOfOne<CustomCollection<UInt8>> {
31+
fatalError()
32+
}
33+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// RUN: %target-typecheck-verify-swift -enable-experimental-associated-type-inference
2+
// RUN: %target-typecheck-verify-swift -disable-experimental-associated-type-inference
3+
4+
// REQUIRES: objc_interop
5+
6+
import Foundation
7+
8+
public struct CustomCollection<Element>: RandomAccessCollection, MutableCollection, ExpressibleByArrayLiteral {
9+
public typealias Indices = Range<Int>
10+
public typealias Index = Int
11+
12+
public init() {}
13+
14+
public init(arrayLiteral elements: Element ...) {
15+
fatalError()
16+
}
17+
}
18+
19+
extension CustomCollection {
20+
public var startIndex: Int { fatalError() }
21+
public var endIndex: Int { fatalError() }
22+
23+
public subscript(position: Int) -> Element {
24+
get { fatalError() }
25+
set { fatalError() }
26+
}
27+
}
28+
29+
extension CustomCollection: RangeReplaceableCollection {
30+
public mutating func append(_ newElement: Element) { }
31+
public mutating func append<S: Sequence>(contentsOf newElements: S) where S.Element == Element { }
32+
public mutating func reserveCapacity(_ minimumCapacity: Int) { }
33+
public mutating func removeAll(keepingCapacity keepCapacity: Bool = false) { }
34+
public mutating func replaceSubrange<C: Collection>(_ subRange: Range<Int>, with newElements: C) where C.Element == Element { }
35+
}
36+
37+
extension CustomCollection {
38+
public func withUnsafeBytes<R>(_ body: (UnsafeRawBufferPointer) throws -> R) rethrows -> R { fatalError() }
39+
}
40+
41+
extension CustomCollection: ContiguousBytes where Element == UInt8 { }
42+
43+
extension CustomCollection: DataProtocol where Element == UInt8 {
44+
public var regions: CollectionOfOne<CustomCollection<UInt8>> { fatalError() }
45+
}

test/decl/protocol/req/associated_type_inference_stdlib_3.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
// RUN: not %target-typecheck-verify-swift -enable-experimental-associated-type-inference
1+
// RUN: %target-typecheck-verify-swift -enable-experimental-associated-type-inference
22
// RUN: not %target-typecheck-verify-swift -disable-experimental-associated-type-inference
33

4-
// FIXME: Get this passing with -enable-experimental-associated-type-inference again.
5-
64
struct FooIterator<T: Sequence>: IteratorProtocol {
75
typealias Element = T.Element
86

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// RUN: %target-typecheck-verify-swift -enable-experimental-associated-type-inference
2+
// RUN: %target-typecheck-verify-swift -disable-experimental-associated-type-inference
3+
4+
struct CustomCollection<T>: RandomAccessCollection {
5+
struct CustomIndices: RandomAccessCollection {
6+
var count: Int { fatalError() }
7+
8+
var startIndex: Int { fatalError() }
9+
var endIndex: Int { fatalError() }
10+
11+
subscript(index: Int) -> Int { fatalError() }
12+
}
13+
14+
var count: Int { fatalError() }
15+
var indices: CustomIndices { fatalError() }
16+
var startIndex: Int { fatalError() }
17+
var endIndex: Int { fatalError() }
18+
func index(before i: Int) -> Int { fatalError() }
19+
func index(after i: Int) -> Int { fatalError() }
20+
subscript(index: Int) -> T { fatalError() }
21+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
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 P {
5+
associatedtype A = Never
6+
}
7+
8+
public struct G<A>: P {}
9+
10+
public struct ConcreteA {}
11+
12+
public protocol Q: P where Self.A == ConcreteA {}
13+
14+
extension G: Q where A == ConcreteA {}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// RUN: %target-typecheck-verify-swift -enable-experimental-associated-type-inference
2+
// RUN: not %target-typecheck-verify-swift -disable-experimental-associated-type-inference
3+
4+
func f<T: Sequence>(_: T) -> T.Element {}
5+
6+
let x: Int = f(CustomCollection<Int>())
7+
8+
struct CustomCollection<Element>: RandomAccessCollection, MutableCollection {
9+
typealias SubSequence = ArraySlice<Element>
10+
typealias Index = Int
11+
typealias Indices = Range<Int>
12+
13+
var startIndex: Int { fatalError() }
14+
var endIndex: Int { fatalError() }
15+
var first: Element? { fatalError() }
16+
var last: Element? { fatalError() }
17+
18+
subscript(position: Index) -> Element {
19+
get { fatalError() }
20+
set { fatalError() }
21+
}
22+
23+
subscript(bounds: Indices) -> SubSequence {
24+
get { fatalError() }
25+
set { fatalError() }
26+
}
27+
}
28+
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// RUN: %target-typecheck-verify-swift -enable-experimental-associated-type-inference
2+
// RUN: %target-typecheck-verify-swift -disable-experimental-associated-type-inference
3+
4+
struct G1<T> {}
5+
6+
struct G2<A, B>: AP {
7+
func f1(_: G1<(B) -> A>, _: G1<B>) -> G1<A> { fatalError() }
8+
func f2<C>(_: (A) -> C) -> G1<C> { fatalError() }
9+
}
10+
11+
protocol OP: EP {
12+
associatedtype L
13+
associatedtype R
14+
15+
func f1(_: G1<L>, _: G1<R>) -> G1<A>
16+
}
17+
18+
extension OP {
19+
func f1(_: G1<L>?, _: G1<R>?) -> G1<A> { fatalError() }
20+
}
21+
22+
protocol AP: OP where L == (B) -> A, R == B {}
23+
24+
protocol EP {
25+
associatedtype A
26+
associatedtype B
27+
func f2<C>(_: (A) -> C) -> G1<C>
28+
}

0 commit comments

Comments
 (0)