Skip to content

Commit 7d62605

Browse files
committed
[stdlib] fix an accidental recursion bug involving Collection
- adds a default implementation of Collection’s subscript(bounds: Range<_>) with the most general signature possible - it is marked unavailable in order to prevent the infinite recursion bug reported in SR-14848 - Collections whose SubSequence is Slice<Self> still get the proper default, as intended.
1 parent b8900de commit 7d62605

File tree

2 files changed

+31
-0
lines changed

2 files changed

+31
-0
lines changed

stdlib/public/core/Collection.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1044,6 +1044,18 @@ extension Collection where SubSequence == Slice<Self> {
10441044
}
10451045
}
10461046

1047+
extension Collection {
1048+
// This unavailable default implementation of `subscript(bounds: Range<_>)`
1049+
// prevents incomplete Collection implementations from satisfying the
1050+
// protocol through the use of the generic convenience implementation
1051+
// `subscript<R: RangeExpression>(r: R)`. If that were the case, at
1052+
// runtime the generic implementation would call itself
1053+
// in an infinite recursion because of the absence of a better option.
1054+
@available(*, unavailable)
1055+
@_alwaysEmitIntoClient
1056+
public subscript(bounds: Range<Index>) -> SubSequence { fatalError() }
1057+
}
1058+
10471059
extension Collection where SubSequence == Self {
10481060
/// Removes and returns the first element of the collection.
10491061
///

validation-test/stdlib/CollectionDiagnostics.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,25 @@ struct RangeReplaceableCollection_SubSequence_IsDefaulted : RangeReplaceableColl
135135
}
136136
}
137137

138+
//
139+
// A Collection that does not use `Slice<Self>` as its SubSequence should
140+
// require its own implementation of the Range<Index> subscript getter.
141+
// The only valid default implementation of that Collection requirement
142+
// returns `Slice<Self>`.
143+
//
144+
145+
// expected-error@+2 {{type 'CollectionWithNonDefaultSubSequence' does not conform to protocol 'Collection'}}
146+
// expected-error@+1 {{unavailable subscript 'subscript(_:)' was used to satisfy a requirement of protocol 'Collection'}}
147+
struct CollectionWithNonDefaultSubSequence: Collection {
148+
public var startIndex: Int
149+
public var endIndex: Int
150+
151+
public typealias SubSequence = Self
152+
153+
public func index(after i: Int) -> Int { i+1 }
154+
public subscript(position: Int) -> Int { position }
155+
}
156+
138157
// FIXME: Remove -verify-ignore-unknown.
139158
// <unknown>:0: error: unexpected note produced: possibly intended match
140159
// <unknown>:0: error: unexpected note produced: possibly intended match

0 commit comments

Comments
 (0)