Skip to content

Commit 24a1828

Browse files
committed
Replace rethrowing map with generic typed throws
Adopt typed throws for the `map` operation to propagate thrown error types through the `map` API. This is done in a manner that is backward compatible for almost all cases: * The new typed-throws entrypoint is `@_alwaysEmitIntoClient` so it can back-deploy all the way back. * The old `rethrows` entrypoint is left in place, using `@usableFromInline` with `internal` so it is part of the ABI but not the public interface, and `@_disfavoredOverload` so the type checker avoids it while building the standard library itself. The old entrypoint is implemented in terms of the new one. Note that the implementation details for the existential collection "box" classes rely on method overriding of `_map` operations, and the types are frozen, so we don't get to change their signatures. However, these are only implementations, not API: the actual API `map` functions can be upgraded to typed throws. Note that this code makes use of a known hole in `rethrows` checking to allow calling between `rethrows` and typed throws. We'll need to do something about this for source-compatibility reasons, but I'll follow up with that separately.
1 parent bb8cb7d commit 24a1828

File tree

4 files changed

+155
-18
lines changed

4 files changed

+155
-18
lines changed

stdlib/public/core/Collection.swift

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1190,9 +1190,10 @@ extension Collection {
11901190
/// - Returns: An array containing the transformed elements of this
11911191
/// sequence.
11921192
@inlinable
1193-
public func map<T>(
1194-
_ transform: (Element) throws -> T
1195-
) rethrows -> [T] {
1193+
@_alwaysEmitIntoClient
1194+
public func map<T, E>(
1195+
_ transform: (Element) throws(E) -> T
1196+
) throws(E) -> [T] {
11961197
// TODO: swift-3-indexing-model - review the following
11971198
let n = self.count
11981199
if n == 0 {
@@ -1213,6 +1214,20 @@ extension Collection {
12131214
return Array(result)
12141215
}
12151216

1217+
// ABI-only entrypoint
1218+
@usableFromInline
1219+
@_disfavoredOverload
1220+
func map<T>(
1221+
_ transform: (Element) throws -> T
1222+
) rethrows -> [T] {
1223+
do {
1224+
return try map(transform)
1225+
} catch {
1226+
try _rethrowsViaClosure { throw error }
1227+
Builtin.unreachable()
1228+
}
1229+
}
1230+
12161231
/// Returns a subsequence containing all but the given number of initial
12171232
/// elements.
12181233
///

stdlib/public/core/ExistentialCollection.swift

Lines changed: 108 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -526,7 +526,12 @@ internal final class _SequenceBox<S: Sequence>: _AnySequenceBox<S.Element> {
526526
internal override func _map<T>(
527527
_ transform: (Element) throws -> T
528528
) rethrows -> [T] {
529-
return try _base.map(transform)
529+
do {
530+
return try _base.map(transform)
531+
} catch {
532+
try _rethrowsViaClosure { throw error }
533+
Builtin.unreachable()
534+
}
530535
}
531536
@inlinable
532537
internal override func _filter(
@@ -619,7 +624,12 @@ internal final class _CollectionBox<S: Collection>: _AnyCollectionBox<S.Element>
619624
internal override func _map<T>(
620625
_ transform: (Element) throws -> T
621626
) rethrows -> [T] {
622-
return try _base.map(transform)
627+
do {
628+
return try _base.map(transform)
629+
} catch {
630+
try _rethrowsViaClosure { throw error }
631+
Builtin.unreachable()
632+
}
623633
}
624634
@inlinable
625635
internal override func _filter(
@@ -814,7 +824,12 @@ internal final class _BidirectionalCollectionBox<S: BidirectionalCollection>
814824
internal override func _map<T>(
815825
_ transform: (Element) throws -> T
816826
) rethrows -> [T] {
817-
return try _base.map(transform)
827+
do {
828+
return try _base.map(transform)
829+
} catch {
830+
try _rethrowsViaClosure { throw error }
831+
Builtin.unreachable()
832+
}
818833
}
819834
@inlinable
820835
internal override func _filter(
@@ -1027,7 +1042,12 @@ internal final class _RandomAccessCollectionBox<S: RandomAccessCollection>
10271042
internal override func _map<T>(
10281043
_ transform: (Element) throws -> T
10291044
) rethrows -> [T] {
1030-
return try _base.map(transform)
1045+
do {
1046+
return try _base.map(transform)
1047+
} catch {
1048+
try _rethrowsViaClosure { throw error }
1049+
Builtin.unreachable()
1050+
}
10311051
}
10321052
@inlinable
10331053
internal override func _filter(
@@ -1303,10 +1323,29 @@ extension AnySequence {
13031323
}
13041324

13051325
@inlinable
1306-
public func map<T>(
1326+
@_alwaysEmitIntoClient
1327+
public func map<T, E>(
1328+
_ transform: (Element) throws(E) -> T
1329+
) throws(E) -> [T] {
1330+
do {
1331+
return try _box._map(transform)
1332+
} catch {
1333+
throw error as! E
1334+
}
1335+
}
1336+
1337+
// ABI-only entrypoint
1338+
@usableFromInline
1339+
@_disfavoredOverload
1340+
func map<T>(
13071341
_ transform: (Element) throws -> T
13081342
) rethrows -> [T] {
1309-
return try _box._map(transform)
1343+
do {
1344+
return try map(transform)
1345+
} catch {
1346+
try _rethrowsViaClosure { throw error }
1347+
Builtin.unreachable()
1348+
}
13101349
}
13111350

13121351
@inlinable
@@ -1390,10 +1429,29 @@ extension AnyCollection {
13901429
}
13911430

13921431
@inlinable
1393-
public func map<T>(
1432+
@_alwaysEmitIntoClient
1433+
public func map<T, E>(
1434+
_ transform: (Element) throws(E) -> T
1435+
) throws(E) -> [T] {
1436+
do {
1437+
return try _box._map(transform)
1438+
} catch {
1439+
throw error as! E
1440+
}
1441+
}
1442+
1443+
// ABI-only entrypoint
1444+
@usableFromInline
1445+
@_disfavoredOverload
1446+
func map<T>(
13941447
_ transform: (Element) throws -> T
13951448
) rethrows -> [T] {
1396-
return try _box._map(transform)
1449+
do {
1450+
return try map(transform)
1451+
} catch {
1452+
try _rethrowsViaClosure { throw error }
1453+
Builtin.unreachable()
1454+
}
13971455
}
13981456

13991457
@inlinable
@@ -1483,10 +1541,29 @@ extension AnyBidirectionalCollection {
14831541
}
14841542

14851543
@inlinable
1486-
public func map<T>(
1544+
@_alwaysEmitIntoClient
1545+
public func map<T, E>(
1546+
_ transform: (Element) throws(E) -> T
1547+
) throws(E) -> [T] {
1548+
do {
1549+
return try _box._map(transform)
1550+
} catch {
1551+
throw error as! E
1552+
}
1553+
}
1554+
1555+
// ABI-only entrypoint
1556+
@usableFromInline
1557+
@_disfavoredOverload
1558+
func map<T>(
14871559
_ transform: (Element) throws -> T
14881560
) rethrows -> [T] {
1489-
return try _box._map(transform)
1561+
do {
1562+
return try map(transform)
1563+
} catch {
1564+
try _rethrowsViaClosure { throw error }
1565+
Builtin.unreachable()
1566+
}
14901567
}
14911568

14921569
@inlinable
@@ -1578,10 +1655,29 @@ extension AnyRandomAccessCollection {
15781655
}
15791656

15801657
@inlinable
1581-
public func map<T>(
1658+
@_alwaysEmitIntoClient
1659+
public func map<T, E>(
1660+
_ transform: (Element) throws(E) -> T
1661+
) throws(E) -> [T] {
1662+
do {
1663+
return try _box._map(transform)
1664+
} catch {
1665+
throw error as! E
1666+
}
1667+
}
1668+
1669+
// ABI-only entrypoint
1670+
@usableFromInline
1671+
@_disfavoredOverload
1672+
func map<T>(
15821673
_ transform: (Element) throws -> T
15831674
) rethrows -> [T] {
1584-
return try _box._map(transform)
1675+
do {
1676+
return try map(transform)
1677+
} catch {
1678+
try _rethrowsViaClosure { throw error }
1679+
Builtin.unreachable()
1680+
}
15851681
}
15861682

15871683
@inlinable

stdlib/public/core/Misc.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,17 @@ public func _unsafePerformance<T>(_ c: () -> T) -> T {
159159
return c()
160160
}
161161

162+
// Helper function that exploits a bug in rethrows checking to
163+
// allow us to call rethrows functions from generic typed-throws functions
164+
// and vice-versa.
165+
@usableFromInline
166+
@_alwaysEmitIntoClient
167+
@inline(__always)
168+
func _rethrowsViaClosure(_ fn: () throws -> ()) rethrows {
169+
try fn()
170+
}
171+
172+
162173
/// This marker protocol represents types that support copying.
163174
/// This type is not yet available for use to express explicit
164175
/// constraints on generics in your programs. It is currently

stdlib/public/core/Sequence.swift

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -670,9 +670,10 @@ extension Sequence {
670670
///
671671
/// - Complexity: O(*n*), where *n* is the length of the sequence.
672672
@inlinable
673-
public func map<T>(
674-
_ transform: (Element) throws -> T
675-
) rethrows -> [T] {
673+
@_alwaysEmitIntoClient
674+
public func map<T, E>(
675+
_ transform: (Element) throws(E) -> T
676+
) throws(E) -> [T] {
676677
let initialCapacity = underestimatedCount
677678
var result = ContiguousArray<T>()
678679
result.reserveCapacity(initialCapacity)
@@ -690,6 +691,20 @@ extension Sequence {
690691
return Array(result)
691692
}
692693

694+
// ABI-only entrypoint
695+
@usableFromInline
696+
@_disfavoredOverload
697+
func map<T>(
698+
_ transform: (Element) throws -> T
699+
) rethrows -> [T] {
700+
do {
701+
return try map(transform)
702+
} catch {
703+
try _rethrowsViaClosure { throw error }
704+
Builtin.unreachable()
705+
}
706+
}
707+
693708
/// Returns an array containing, in order, the elements of the sequence
694709
/// that satisfy the given predicate.
695710
///

0 commit comments

Comments
 (0)