Skip to content

Commit 805c57f

Browse files
authored
Don't use AnyKeyPath.debugDescription due to crash (#81)
* Don't use `AnyKeyPath.debugDescription` due to crash SE-0369's implementation unfortunately has a crash related to dynamic member lookup, so we should revert our reliance on it till the bug is fixed. See swiftlang/swift#64865 for more info. * wip * wip * wip
1 parent 6a90124 commit 805c57f

File tree

3 files changed

+101
-56
lines changed

3 files changed

+101
-56
lines changed

Sources/CustomDump/Conformances/KeyPath.swift

+15-8
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@ import Foundation
22

33
extension AnyKeyPath: CustomDumpStringConvertible {
44
public var customDumpDescription: String {
5-
#if swift(>=5.8)
6-
if #available(macOS 13.3, iOS 16.4, watchOS 9.4, tvOS 16.4, *) {
7-
return self.debugDescription
8-
}
9-
#endif
5+
// NB: We can't currently rely on SE-0369 due to this crasher:
6+
// https://github.com/apple/swift/issues/64865
7+
//
8+
// #if swift(>=5.8)
9+
// if #available(macOS 13.3, iOS 16.4, watchOS 9.4, tvOS 16.4, *) {
10+
// return self.debugDescription
11+
// }
12+
// #endif
1013
#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS)
1114
keyPathToNameLock.lock()
1215
defer { keyPathToNameLock.unlock() }
@@ -27,7 +30,11 @@ extension AnyKeyPath: CustomDumpStringConvertible {
2730
}
2831
}
2932
}
30-
return String(describing: type(of: self))
33+
return """
34+
\(typeName(Self.self))<\
35+
\(typeName(Self.rootType, genericsAbbreviated: false)), \
36+
\(typeName(Self.valueType, genericsAbbreviated: false))>
37+
"""
3138
}
3239
let name = reflectName()
3340
keyPathToName[self] = name
@@ -37,8 +44,8 @@ extension AnyKeyPath: CustomDumpStringConvertible {
3744
#else
3845
return """
3946
\(typeName(Self.self))<\
40-
\(typeName(Self.rootType)), \
41-
\(typeName(Self.valueType,genericsAbbreviated: false))>
47+
\(typeName(Self.rootType, genericsAbbreviated: false)), \
48+
\(typeName(Self.valueType, genericsAbbreviated: false))>
4249
"""
4350
#endif
4451
}

Tests/CustomDumpTests/DumpTests.swift

+81-48
Original file line numberDiff line numberDiff line change
@@ -686,8 +686,73 @@ final class DumpTests: XCTestCase {
686686
func testKeyPath() {
687687
var dump = ""
688688

689-
#if swift(>=5.8)
690-
if #available(macOS 13.3, iOS 16.4, watchOS 9.4, tvOS 16.4, *) {
689+
// NB: This code path marks the expectation of relying on SE-0369's
690+
// `AnyKeyPath.debugDescription`, which currently has a crash related to dynamic member lookup:
691+
// https://github.com/apple/swift/issues/64865
692+
//
693+
// #if swift(>=5.8)
694+
// if #available(macOS 13.3, iOS 16.4, watchOS 9.4, tvOS 16.4, *) {
695+
// dump = ""
696+
// customDump(\UserClass.name, to: &dump)
697+
// XCTAssertNoDifference(
698+
// dump,
699+
// #"""
700+
// \UserClass.name
701+
// """#
702+
// )
703+
//
704+
// dump = ""
705+
// customDump(\Pair.driver.name, to: &dump)
706+
// XCTAssertNoDifference(
707+
// dump,
708+
// #"""
709+
// \Pair.driver.name
710+
// """#
711+
// )
712+
//
713+
// dump = ""
714+
// customDump(\User.name.count, to: &dump)
715+
// XCTAssertNoDifference(
716+
// dump,
717+
// #"""
718+
// \User.name.count
719+
// """#
720+
// )
721+
//
722+
// dump = ""
723+
// customDump(\(x: Double, y: Double).x, to: &dump)
724+
// XCTAssertNoDifference(
725+
// dump,
726+
// #"""
727+
// \(x: Double, y: Double).x
728+
// """#
729+
// )
730+
//
731+
// dump = ""
732+
// customDump(\Item.$isInStock, to: &dump)
733+
// XCTAssertNoDifference(
734+
// dump,
735+
// #"""
736+
// \Item.$isInStock
737+
// """#
738+
// )
739+
//
740+
// // NB: This currently crashes when using Swift's `debugDescription`:
741+
// // https://github.com/apple/swift/issues/64865
742+
// dump = ""
743+
// customDump(\Wrapped<String>.count, to: &dump)
744+
// XCTAssertNoDifference(
745+
// dump,
746+
// #"""
747+
// \Wrapped.count
748+
// """#
749+
// )
750+
// return
751+
// }
752+
// #endif
753+
#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS)
754+
// Run twice to exercise cached lookup
755+
for _ in 1...2 {
691756
dump = ""
692757
customDump(\UserClass.name, to: &dump)
693758
XCTAssertNoDifference(
@@ -711,7 +776,7 @@ final class DumpTests: XCTestCase {
711776
XCTAssertNoDifference(
712777
dump,
713778
#"""
714-
\User.name.count
779+
KeyPath<User, Int>
715780
"""#
716781
)
717782

@@ -720,7 +785,7 @@ final class DumpTests: XCTestCase {
720785
XCTAssertNoDifference(
721786
dump,
722787
#"""
723-
\(x: Double, y: Double).x
788+
WritableKeyPath<(x: Double, y: Double), Double>
724789
"""#
725790
)
726791

@@ -729,57 +794,16 @@ final class DumpTests: XCTestCase {
729794
XCTAssertNoDifference(
730795
dump,
731796
#"""
732-
\Item.$isInStock
733-
"""#
734-
)
735-
return
736-
}
737-
#endif
738-
#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS)
739-
// Run twice to exercise cached lookup
740-
for _ in 1...2 {
741-
dump = ""
742-
customDump(\UserClass.name, to: &dump)
743-
XCTAssertNoDifference(
744-
dump,
745-
#"""
746-
\UserClass.name
747-
"""#
748-
)
749-
750-
dump = ""
751-
customDump(\Pair.driver.name, to: &dump)
752-
XCTAssertNoDifference(
753-
dump,
754-
#"""
755-
\Pair.driver.name
756-
"""#
757-
)
758-
759-
dump = ""
760-
customDump(\User.name.count, to: &dump)
761-
XCTAssertNoDifference(
762-
dump,
763-
#"""
764-
KeyPath<User, Int>
765-
"""#
766-
)
767-
768-
dump = ""
769-
customDump(\(x: Double, y: Double).x, to: &dump)
770-
XCTAssertNoDifference(
771-
dump,
772-
#"""
773-
WritableKeyPath<(x: Double, y: Double), Double>
797+
KeyPath<Item, Wrapped<Bool>>
774798
"""#
775799
)
776800

777801
dump = ""
778-
customDump(\Item.$isInStock, to: &dump)
802+
customDump(\Wrapped<String>.count, to: &dump)
779803
XCTAssertNoDifference(
780804
dump,
781805
#"""
782-
KeyPath<Item, Wrapped<Bool>>
806+
KeyPath<Wrapped<String>, Int>
783807
"""#
784808
)
785809
}
@@ -828,6 +852,15 @@ final class DumpTests: XCTestCase {
828852
KeyPath<Item, Wrapped<Bool>>
829853
"""#
830854
)
855+
856+
dump = ""
857+
customDump(\Wrapped<String>.count, to: &dump)
858+
XCTAssertNoDifference(
859+
dump,
860+
#"""
861+
KeyPath<Wrapped<String>, Int>
862+
"""#
863+
)
831864
#endif
832865
}
833866

Tests/CustomDumpTests/Mocks.swift

+5
Original file line numberDiff line numberDiff line change
@@ -130,10 +130,15 @@ struct Redacted<RawValue>: CustomDumpStringConvertible {
130130
struct User: Equatable, Identifiable { var id: Int, name: String }
131131
struct HashableUser: Equatable, Identifiable, Hashable { var id: Int, name: String }
132132

133+
@dynamicMemberLookup
133134
@propertyWrapper
134135
struct Wrapped<Value> {
135136
var wrappedValue: Value
136137
var projectedValue: Self { self }
138+
139+
subscript<NewValue>(dynamicMember keyPath: KeyPath<Value, NewValue>) -> NewValue {
140+
self.wrappedValue[keyPath: keyPath]
141+
}
137142
}
138143

139144
struct Item {

0 commit comments

Comments
 (0)