Skip to content

Commit e381815

Browse files
committed
Add a conditional identity cast
1 parent dd813af commit e381815

File tree

2 files changed

+34
-0
lines changed

2 files changed

+34
-0
lines changed

stdlib/public/core/Builtin.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,21 @@ public func _identityCast<T, U>(_ x: T, to expectedType: U.Type) -> U {
109109
return Builtin.reinterpretCast(x)
110110
}
111111

112+
/// Returns `x` as its concrete type `U`.
113+
///
114+
/// This cast can be useful for dispatching to specializations of generic
115+
/// functions.
116+
///
117+
/// - Requires: `x` has type `U`.
118+
@_alwaysEmitIntoClient
119+
public func _conditionalIdentityCast<T, U>(_ x: T, to: U.Type) -> U? {
120+
guard T.self == U.self else {
121+
return nil
122+
}
123+
124+
return Builtin.reinterpretCast(x)
125+
}
126+
112127
/// `unsafeBitCast` something to `AnyObject`.
113128
@usableFromInline @_transparent
114129
internal func _reinterpretCastToAnyObject<T>(_ x: T) -> AnyObject {

test/stdlib/Builtins.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,4 +307,23 @@ tests.test("_isConcrete") {
307307
expectFalse(isConcrete_false(Int.self))
308308
}
309309

310+
tests.test("_conditionalIdentityCast") {
311+
func something<T>(with x: some Collection<T>) -> Int {
312+
if let y = _conditionalIdentityCast(x, to: [Int].self) {
313+
return y[0]
314+
} else {
315+
return 1234567890
316+
}
317+
}
318+
319+
let x = [0987654321, 1, 2]
320+
expectEqual(something(with: x), 0987654321)
321+
322+
let y = CollectionOfOne<String>("hello world")
323+
expectEqual(something(with: y), 1234567890)
324+
325+
let z: Any = [0, 1, 2, 3]
326+
expectNil(_conditionalIdentityCast(z, to: [Int].self))
327+
}
328+
310329
runAllTests()

0 commit comments

Comments
 (0)