Skip to content

Commit c4f0b5f

Browse files
[stdlib] Adopt conditional conformance for Indices, Slice, ReversedCollection (#12913)
* Refactor Indices and Slice to use conditional conformance * Replace ReversedRandomAccessCollection with a conditional extension * Refactor some types into struct+extensions * Revise Slice documentation * Fix test cases for adoption of conditional conformances. * [RangeReplaceableCollection] Eliminate unnecessary slicing subscript operator. * Add -enable-experimental-conditional-conformances to test. * Gruesome workaround for crasher in MutableSlice tests
1 parent eea5e5d commit c4f0b5f

25 files changed

+347
-680
lines changed

stdlib/private/StdlibCollectionUnittest/CheckMutableCollectionType.swift.gyb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,8 @@ self.test("\(testNamePrefix).subscript(_: Range)/Set/semantics") {
276276
// Call setter implicitly through an inout mutation.
277277
var c = makeWrappedCollection(test.collection)
278278

279-
_mapInPlace(&c[test.bounds(in: c)]) {
279+
var s = c[test.bounds(in: c)]
280+
_mapInPlace(&s) {
280281
wrapValue(OpaqueValue(extractValue($0).value + 90000))
281282
}
282283

stdlib/public/core/BidirectionalCollection.swift

Lines changed: 8 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,20 @@ public typealias BidirectionalIndexable = BidirectionalCollection
4444
/// `c.index(before: c.index(after: i)) == i`.
4545
/// - If `i > c.startIndex && i <= c.endIndex`
4646
/// `c.index(after: c.index(before: i)) == i`.
47-
public protocol BidirectionalCollection : Collection
48-
{
47+
public protocol BidirectionalCollection: Collection
48+
where SubSequence: BidirectionalCollection, Indices: BidirectionalCollection {
4949
// FIXME(ABI): Associated type inference requires this.
5050
associatedtype Element
5151

5252
// FIXME(ABI): Associated type inference requires this.
5353
associatedtype Index
5454

55+
// FIXME(ABI): Associated type inference requires this.
56+
associatedtype SubSequence = Slice<Self>
57+
58+
// FIXME(ABI): Associated type inference requires this.
59+
associatedtype Indices = DefaultIndices<Self>
60+
5561
/// Returns the position immediately before the given index.
5662
///
5763
/// - Parameter i: A valid index of the collection. `i` must be greater than
@@ -65,16 +71,6 @@ public protocol BidirectionalCollection : Collection
6571
/// `startIndex`.
6672
func formIndex(before i: inout Index)
6773

68-
/// A sequence that can represent a contiguous subrange of the collection's
69-
/// elements.
70-
associatedtype SubSequence : BidirectionalCollection
71-
= BidirectionalSlice<Self>
72-
73-
/// A type that represents the indices that are valid for subscripting the
74-
/// collection, in ascending order.
75-
associatedtype Indices : BidirectionalCollection
76-
= DefaultBidirectionalIndices<Self>
77-
7874
/// The indices that are valid for subscripting the collection, in ascending
7975
/// order.
8076
///
@@ -201,17 +197,6 @@ extension BidirectionalCollection {
201197
}
202198
}
203199

204-
/// Supply the default "slicing" `subscript` for `BidirectionalCollection`
205-
/// models that accept the default associated `SubSequence`,
206-
/// `BidirectionalSlice<Self>`.
207-
extension BidirectionalCollection where SubSequence == BidirectionalSlice<Self> {
208-
@_inlineable // FIXME(sil-serialize-all)
209-
public subscript(bounds: Range<Index>) -> BidirectionalSlice<Self> {
210-
_failEarlyRangeCheck(bounds, bounds: startIndex..<endIndex)
211-
return BidirectionalSlice(base: self, bounds: bounds)
212-
}
213-
}
214-
215200
extension BidirectionalCollection where SubSequence == Self {
216201
/// Removes and returns the last element of the collection.
217202
///

stdlib/public/core/CMakeLists.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ set(SWIFTLIB_ESSENTIAL
7272
HeapBuffer.swift
7373
ICU.swift
7474
ImplicitlyUnwrappedOptional.swift
75-
Indices.swift.gyb
75+
Indices.swift
7676
InputStream.swift
7777
IntegerParsing.swift
7878
Integers.swift.gyb
@@ -100,7 +100,7 @@ set(SWIFTLIB_ESSENTIAL
100100
Print.swift
101101
RandomAccessCollection.swift
102102
Range.swift.gyb
103-
RangeReplaceableCollection.swift.gyb
103+
RangeReplaceableCollection.swift
104104
ReflectionLegacy.swift
105105
Repeat.swift
106106
REPL.swift
@@ -115,7 +115,7 @@ set(SWIFTLIB_ESSENTIAL
115115
SetAlgebra.swift
116116
ShadowProtocols.swift
117117
Shims.swift
118-
Slice.swift.gyb
118+
Slice.swift
119119
Sort.swift.gyb
120120
StaticString.swift
121121
Stride.swift.gyb

stdlib/public/core/ClosedRange.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -261,8 +261,8 @@ public struct CountableClosedRange<Bound> : RandomAccessCollection
261261

262262
@_inlineable
263263
public subscript(bounds: Range<Index>)
264-
-> RandomAccessSlice<CountableClosedRange<Bound>> {
265-
return RandomAccessSlice(base: self, bounds: bounds)
264+
-> Slice<CountableClosedRange<Bound>> {
265+
return Slice(base: self, bounds: bounds)
266266
}
267267

268268
/// Creates an instance with the given bounds.

stdlib/public/core/Collection.swift

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,11 @@ public typealias Indexable = Collection
8282
/// // Prints "15.0"
8383
/// // Prints "20.0"
8484
@_fixed_layout
85-
public struct IndexingIterator<
86-
Elements : Collection
87-
> : IteratorProtocol, Sequence {
85+
public struct IndexingIterator<Elements : Collection> {
86+
@_versioned
87+
internal let _elements: Elements
88+
@_versioned
89+
internal var _position: Elements.Index
8890

8991
@_inlineable
9092
@inline(__always)
@@ -103,6 +105,12 @@ public struct IndexingIterator<
103105
self._elements = _elements
104106
self._position = _position
105107
}
108+
}
109+
110+
extension IndexingIterator: IteratorProtocol, Sequence {
111+
public typealias Element = Elements.Element
112+
public typealias Iterator = IndexingIterator<Elements>
113+
public typealias SubSequence = AnySequence<Element>
106114

107115
/// Advances to the next element and returns it, or `nil` if no next element
108116
/// exists.
@@ -136,11 +144,6 @@ public struct IndexingIterator<
136144
_elements.formIndex(after: &_position)
137145
return element
138146
}
139-
140-
@_versioned
141-
internal let _elements: Elements
142-
@_versioned
143-
internal var _position: Elements.Index
144147
}
145148

146149
/// A sequence whose elements can be traversed multiple times,
@@ -345,8 +348,7 @@ public struct IndexingIterator<
345348
/// or bidirectional collection must traverse the entire collection to count
346349
/// the number of contained elements, accessing its `count` property is an
347350
/// O(*n*) operation.
348-
public protocol Collection : Sequence
349-
{
351+
public protocol Collection: Sequence where SubSequence: Collection {
350352
// FIXME(ABI): Associated type inference requires this.
351353
associatedtype Element
352354

@@ -403,7 +405,7 @@ public protocol Collection : Sequence
403405
/// This associated type appears as a requirement in the `Sequence`
404406
/// protocol, but it is restated here with stricter constraints. In a
405407
/// collection, the subsequence should also conform to `Collection`.
406-
associatedtype SubSequence : Collection = Slice<Self>
408+
associatedtype SubSequence = Slice<Self>
407409
where SubSequence.Index == Index,
408410
SubSequence.IndexDistance == IndexDistance
409411

stdlib/public/core/CollectionOfOne.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,10 @@ public struct CollectionOfOne<Element>
109109

110110
@_inlineable // FIXME(sil-serialize-all)
111111
public subscript(bounds: Range<Int>)
112-
-> MutableRandomAccessSlice<CollectionOfOne<Element>> {
112+
-> Slice<CollectionOfOne<Element>> {
113113
get {
114114
_failEarlyRangeCheck(bounds, bounds: startIndex..<endIndex)
115-
return MutableRandomAccessSlice(base: self, bounds: bounds)
115+
return Slice(base: self, bounds: bounds)
116116
}
117117
set {
118118
_failEarlyRangeCheck(bounds, bounds: startIndex..<endIndex)

stdlib/public/core/Flatten.swift.gyb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -362,8 +362,8 @@ public struct ${Collection}<Base> : ${collectionForTraversal(traversal)}
362362

363363
@_inlineable // FIXME(sil-serialize-all)
364364
public subscript(bounds: Range<Index>)
365-
-> ${Slice}<${Collection}> {
366-
return ${Slice}(base: self, bounds: bounds)
365+
-> Slice<${Collection}> {
366+
return Slice(base: self, bounds: bounds)
367367
}
368368

369369
// To return any estimate of the number of elements, we have to start

stdlib/public/core/Indices.swift.gyb renamed to stdlib/public/core/Indices.swift

Lines changed: 36 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -10,32 +10,15 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13-
%{
14-
from gyb_stdlib_support import (
15-
TRAVERSALS,
16-
collectionForTraversal,
17-
defaultIndicesForTraversal,
18-
documentationNameForTraversal
19-
)
20-
}%
21-
22-
% for Traversal in TRAVERSALS:
23-
% Self = defaultIndicesForTraversal(Traversal)
24-
% collection = documentationNameForTraversal(Traversal)
25-
26-
// FIXME(ABI)#42 (Conditional Conformance): There should be just one default
27-
// indices type that has conditional conformances to
28-
// `BidirectionalCollection` and `RandomAccessCollection`.
29-
// <rdar://problem/17144340>
30-
31-
/// A collection of indices for an arbitrary ${collection}.
13+
/// A collection of indices for an arbitrary collection
3214
@_fixed_layout
33-
public struct ${Self}<
34-
Elements : ${collectionForTraversal(Traversal)}
35-
> : ${collectionForTraversal(Traversal)} {
36-
37-
public typealias Index = Elements.Index
38-
public typealias Indices = ${Self}<Elements>
15+
public struct DefaultIndices<Elements: Collection> {
16+
@_versioned
17+
internal var _elements: Elements
18+
@_versioned
19+
internal var _startIndex: Elements.Index
20+
@_versioned
21+
internal var _endIndex: Elements.Index
3922

4023
@_inlineable
4124
@_versioned
@@ -48,6 +31,16 @@ public struct ${Self}<
4831
self._startIndex = startIndex
4932
self._endIndex = endIndex
5033
}
34+
}
35+
36+
extension DefaultIndices: Collection {
37+
38+
public typealias Index = Elements.Index
39+
public typealias Element = Elements.Index
40+
public typealias Indices = DefaultIndices<Elements>
41+
public typealias SubSequence = DefaultIndices<Elements>
42+
public typealias IndexDistance = Elements.IndexDistance
43+
public typealias Iterator = IndexingIterator<DefaultIndices<Elements>>
5144

5245
@_inlineable
5346
public var startIndex: Index {
@@ -65,12 +58,10 @@ public struct ${Self}<
6558
return i
6659
}
6760

68-
public typealias SubSequence = ${Self}<Elements>
69-
7061
@_inlineable
71-
public subscript(bounds: Range<Index>) -> ${Self}<Elements> {
62+
public subscript(bounds: Range<Index>) -> DefaultIndices<Elements> {
7263
// FIXME: swift-3-indexing-model: range check.
73-
return ${Self}(
64+
return DefaultIndices(
7465
_elements: _elements,
7566
startIndex: bounds.lowerBound,
7667
endIndex: bounds.upperBound)
@@ -88,7 +79,14 @@ public struct ${Self}<
8879
_elements.formIndex(after: &i)
8980
}
9081

91-
% if Traversal in ['Bidirectional', 'RandomAccess']:
82+
@_inlineable
83+
public var indices: Indices {
84+
return self
85+
}
86+
}
87+
88+
extension DefaultIndices: BidirectionalCollection
89+
where Elements: BidirectionalCollection {
9290
@_inlineable
9391
public func index(before i: Index) -> Index {
9492
// FIXME: swift-3-indexing-model: range check.
@@ -100,23 +98,12 @@ public struct ${Self}<
10098
// FIXME: swift-3-indexing-model: range check.
10199
_elements.formIndex(before: &i)
102100
}
103-
% end
104-
105-
@_inlineable
106-
public var indices: Indices {
107-
return self
108-
}
109-
110-
@_versioned
111-
internal var _elements: Elements
112-
@_versioned
113-
internal var _startIndex: Elements.Index
114-
@_versioned
115-
internal var _endIndex: Elements.Index
116101
}
117102

118-
extension ${collectionForTraversal(Traversal)}
119-
where Indices == ${Self}<Self> {
103+
extension DefaultIndices: RandomAccessCollection
104+
where Elements: RandomAccessCollection { }
105+
106+
extension Collection where Indices == DefaultIndices<Self> {
120107
/// The indices that are valid for subscripting the collection, in ascending
121108
/// order.
122109
///
@@ -135,16 +122,13 @@ where Indices == ${Self}<Self> {
135122
/// }
136123
/// // c == MyFancyCollection([2, 4, 6, 8, 10])
137124
@_inlineable // FIXME(sil-serialize-all)
138-
public var indices: ${Self}<Self> {
139-
return ${Self}(
125+
public var indices: DefaultIndices<Self> {
126+
return DefaultIndices(
140127
_elements: self,
141128
startIndex: self.startIndex,
142129
endIndex: self.endIndex)
143130
}
144131
}
145132

146-
% end
147-
148-
// ${'Local Variables'}:
149-
// eval: (read-only-mode 1)
150-
// End:
133+
public typealias DefaultBidirectionalIndices<T: BidirectionalCollection> = DefaultIndices<T>
134+
public typealias DefaultRandomAccessIndices<T: RandomAccessCollection> = DefaultIndices<T>

stdlib/public/core/Integers.swift.gyb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3208,7 +3208,7 @@ ${assignmentOperatorComment(x.operator, True)}
32083208
@_fixed_layout // FIXME(sil-serialize-all)
32093209
public struct Words : BidirectionalCollection {
32103210
public typealias Indices = CountableRange<Int>
3211-
public typealias SubSequence = BidirectionalSlice<${Self}.Words>
3211+
public typealias SubSequence = Slice<${Self}.Words>
32123212

32133213
@_versioned // FIXME(sil-serialize-all)
32143214
internal var _value: ${Self}

stdlib/public/core/LazyCollection.swift.gyb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,8 @@ extension ${Self} : ${TraversalCollection} {
162162
///
163163
/// - Complexity: O(1)
164164
@_inlineable
165-
public subscript(bounds: Range<Index>) -> ${Slice}<${Self}<Base>> {
166-
return ${Slice}(base: self, bounds: bounds)
165+
public subscript(bounds: Range<Index>) -> Slice<${Self}<Base>> {
166+
return Slice(base: self, bounds: bounds)
167167
}
168168
169169
/// A Boolean value indicating whether the collection is empty.

0 commit comments

Comments
 (0)