Skip to content

Commit 6420eea

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 353fb5d commit 6420eea

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(
@@ -1308,10 +1328,29 @@ extension AnySequence {
13081328
}
13091329

13101330
@inlinable
1311-
public func map<T>(
1331+
@_alwaysEmitIntoClient
1332+
public func map<T, E>(
1333+
_ transform: (Element) throws(E) -> T
1334+
) throws(E) -> [T] {
1335+
do {
1336+
return try _box._map(transform)
1337+
} catch {
1338+
throw error as! E
1339+
}
1340+
}
1341+
1342+
// ABI-only entrypoint
1343+
@usableFromInline
1344+
@_disfavoredOverload
1345+
func map<T>(
13121346
_ transform: (Element) throws -> T
13131347
) rethrows -> [T] {
1314-
return try _box._map(transform)
1348+
do {
1349+
return try map(transform)
1350+
} catch {
1351+
try _rethrowsViaClosure { throw error }
1352+
Builtin.unreachable()
1353+
}
13151354
}
13161355

13171356
@inlinable
@@ -1395,10 +1434,29 @@ extension AnyCollection {
13951434
}
13961435

13971436
@inlinable
1398-
public func map<T>(
1437+
@_alwaysEmitIntoClient
1438+
public func map<T, E>(
1439+
_ transform: (Element) throws(E) -> T
1440+
) throws(E) -> [T] {
1441+
do {
1442+
return try _box._map(transform)
1443+
} catch {
1444+
throw error as! E
1445+
}
1446+
}
1447+
1448+
// ABI-only entrypoint
1449+
@usableFromInline
1450+
@_disfavoredOverload
1451+
func map<T>(
13991452
_ transform: (Element) throws -> T
14001453
) rethrows -> [T] {
1401-
return try _box._map(transform)
1454+
do {
1455+
return try map(transform)
1456+
} catch {
1457+
try _rethrowsViaClosure { throw error }
1458+
Builtin.unreachable()
1459+
}
14021460
}
14031461

14041462
@inlinable
@@ -1488,10 +1546,29 @@ extension AnyBidirectionalCollection {
14881546
}
14891547

14901548
@inlinable
1491-
public func map<T>(
1549+
@_alwaysEmitIntoClient
1550+
public func map<T, E>(
1551+
_ transform: (Element) throws(E) -> T
1552+
) throws(E) -> [T] {
1553+
do {
1554+
return try _box._map(transform)
1555+
} catch {
1556+
throw error as! E
1557+
}
1558+
}
1559+
1560+
// ABI-only entrypoint
1561+
@usableFromInline
1562+
@_disfavoredOverload
1563+
func map<T>(
14921564
_ transform: (Element) throws -> T
14931565
) rethrows -> [T] {
1494-
return try _box._map(transform)
1566+
do {
1567+
return try map(transform)
1568+
} catch {
1569+
try _rethrowsViaClosure { throw error }
1570+
Builtin.unreachable()
1571+
}
14951572
}
14961573

14971574
@inlinable
@@ -1583,10 +1660,29 @@ extension AnyRandomAccessCollection {
15831660
}
15841661

15851662
@inlinable
1586-
public func map<T>(
1663+
@_alwaysEmitIntoClient
1664+
public func map<T, E>(
1665+
_ transform: (Element) throws(E) -> T
1666+
) throws(E) -> [T] {
1667+
do {
1668+
return try _box._map(transform)
1669+
} catch {
1670+
throw error as! E
1671+
}
1672+
}
1673+
1674+
// ABI-only entrypoint
1675+
@usableFromInline
1676+
@_disfavoredOverload
1677+
func map<T>(
15871678
_ transform: (Element) throws -> T
15881679
) rethrows -> [T] {
1589-
return try _box._map(transform)
1680+
do {
1681+
return try map(transform)
1682+
} catch {
1683+
try _rethrowsViaClosure { throw error }
1684+
Builtin.unreachable()
1685+
}
15901686
}
15911687

15921688
@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
@_marker public protocol Copyable {}
164175

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)