Skip to content

Commit e041226

Browse files
committed
[NCGenerics] infinite substitution hack
Workaround for rdar://119950540 when dealing with invertible protocols. This should be sound because "its an invariant that subst() on a conformance returns the same thing as a global lookup with subst() of the conforming type, assuming you don't have overlapping conformances."
1 parent 3a4a84a commit e041226

File tree

2 files changed

+131
-0
lines changed

2 files changed

+131
-0
lines changed

Diff for: lib/AST/ProtocolConformanceRef.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,13 @@ ProtocolConformanceRef::subst(Type origType, InFlightSubstitution &IFS) const {
118118
return ProtocolConformanceRef::forInvalid();
119119
}
120120

121+
// If the type has been fully substituted and the requirement is for
122+
// an invertible protocol, just do a module lookup. This avoids an infinite
123+
// substitution issue by recognizing that these protocols are very simple
124+
// (see rdar://119950540 for the general issue).
125+
if (!substType->hasTypeParameter() && proto->getInvertibleProtocolKind())
126+
return proto->getModuleContext()->lookupConformance(substType, proto);
127+
121128
// Check the conformance map.
122129
// FIXME: Pack element level?
123130
return IFS.lookupConformance(origType->getCanonicalType(), substType, proto,

Diff for: test/Generics/inverse_rdar119950540.swift

+124
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
// RUN: %target-swift-frontend %s -emit-silgen -enable-experimental-feature NoncopyableGenerics > /dev/null
2+
3+
public protocol MyIteratorProtocol<Element> {
4+
associatedtype Element
5+
mutating func next() -> Element?
6+
}
7+
8+
// UnsafeBufferPointer
9+
public struct UBP<Element> {}
10+
11+
public protocol MySequence<Element> {
12+
associatedtype Element
13+
14+
associatedtype Iterator: MyIteratorProtocol where Iterator.Element == Element
15+
16+
__consuming func makeIterator() -> Iterator
17+
18+
func _customContainsEquatableElement(
19+
_ element: Element
20+
) -> Bool?
21+
22+
func withContiguousStorageIfAvailable<R>(
23+
_ body: (_ buffer: UBP<Element>) throws -> R
24+
) rethrows -> R?
25+
}
26+
27+
extension MySequence where Self.Iterator == Self {
28+
public __consuming func makeIterator() -> Iterator {
29+
return self
30+
}
31+
}
32+
33+
extension MySequence {
34+
public func _customContainsEquatableElement(
35+
_ element: Iterator.Element
36+
) -> Bool? {
37+
return nil
38+
}
39+
40+
public func withContiguousStorageIfAvailable<R>(
41+
_ body: (UBP<Element>) throws -> R
42+
) rethrows -> R? {
43+
return nil
44+
}
45+
}
46+
47+
48+
public struct MyIndexingIterator<Elements: MyCollection> {
49+
}
50+
51+
extension MyIndexingIterator: MyIteratorProtocol, MySequence {
52+
public typealias Element = Elements.Element
53+
public typealias Iterator = MyIndexingIterator<Elements>
54+
public typealias SubSequence = MySequence<Element>
55+
56+
public mutating func next() -> Elements.Element? {
57+
return nil
58+
}
59+
}
60+
61+
public struct MyDefaultIndices<Elements: MyCollection> {}
62+
extension MyDefaultIndices: MyCollection {
63+
public typealias Index = Elements.Index
64+
public typealias Element = Elements.Index
65+
public typealias Indices = MyDefaultIndices<Elements>
66+
public typealias SubSequence = MyDefaultIndices<Elements>
67+
public typealias Iterator = MyIndexingIterator<MyDefaultIndices<Elements>>
68+
69+
public __consuming func makeIterator() -> Iterator { fatalError("todo") }
70+
}
71+
72+
public struct MySlice<Base: MyCollection> {
73+
74+
}
75+
76+
extension MySlice: MyCollection {
77+
public typealias Index = Base.Index
78+
public typealias Indices = Base.Indices
79+
public typealias Element = Base.Element
80+
public typealias SubSequence = MySlice<Base>
81+
public typealias Iterator = MyIndexingIterator<MySlice<Base>>
82+
83+
public __consuming func makeIterator() -> Iterator { fatalError("todo") }
84+
}
85+
86+
public protocol MyCollection<Element>: MySequence {
87+
override associatedtype Element
88+
associatedtype Index /* : Comparable */
89+
90+
associatedtype Iterator = MyIndexingIterator<Self>
91+
92+
associatedtype SubSequence: MyCollection = MySlice<Self>
93+
where SubSequence.Index == Index,
94+
Element == SubSequence.Element,
95+
SubSequence.SubSequence == SubSequence
96+
97+
associatedtype Indices: MyCollection = MyDefaultIndices<Self>
98+
where Indices.Element == Index,
99+
Indices.Index == Index,
100+
Indices.SubSequence == Indices
101+
}
102+
103+
public struct MyRange<Bound> {}
104+
extension MyRange: MySequence {
105+
public typealias Element = Bound
106+
public typealias Iterator = MyIndexingIterator<MyRange<Bound>>
107+
108+
public __consuming func makeIterator() -> Iterator { fatalError("todo") }
109+
}
110+
extension MyRange: MyCollection {
111+
public typealias Index = Bound
112+
public typealias Indices = MyRange<Bound>
113+
public typealias SubSequence = MyRange<Bound>
114+
}
115+
116+
public struct KVPair<Key, Value>: MyCollection {
117+
public typealias Element = (key: Key, value: Value)
118+
public typealias Index = Int
119+
public typealias Indices = MyRange<Int>
120+
public typealias SubSequence = MySlice<KVPair>
121+
122+
public typealias Iterator = MyIndexingIterator<Self>
123+
public __consuming func makeIterator() -> Iterator { fatalError("todo") }
124+
}

0 commit comments

Comments
 (0)