Skip to content

Commit 081798c

Browse files
authored
Fix crash when creating predicate with generic root type (#1483)
1 parent 4e01366 commit 081798c

File tree

3 files changed

+28
-5
lines changed

3 files changed

+28
-5
lines changed

Sources/FoundationEssentials/Predicate/Archiving/PredicateCodableConfiguration.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ extension PredicateCodableConfiguration {
310310
guard root == rootReflectionType.partial, let constructed = constructor(rootReflectionType.genericArguments) else {
311311
return nil
312312
}
313-
constructed._validateForPredicateUsage(restrictArguments: false)
313+
constructed._validateForPredicateUsage()
314314
return constructed
315315
}
316316
}

Sources/FoundationEssentials/Predicate/KeyPath+Inspection.swift

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ extension UInt32 {
5050
extension AnyKeyPath {
5151
private static var WORD_SIZE: Int { MemoryLayout<Int>.size }
5252

53-
func _validateForPredicateUsage(restrictArguments: Bool = true) {
53+
func _validateForPredicateUsage() {
5454
var ptr = unsafeBitCast(self, to: UnsafeRawPointer.self)
5555
ptr = ptr.advanced(by: Self.WORD_SIZE * 3) // skip isa, type metadata, and KVC string pointers
5656
let header = ptr.load(as: UInt32.self)
@@ -72,9 +72,7 @@ extension AnyKeyPath {
7272
componentWords += 1
7373
}
7474
if firstComponentHeader._keyPathComponentHeader_computedHasArguments {
75-
if restrictArguments {
76-
fatalError("Predicate does not support keypaths with arguments")
77-
}
75+
// TODO: Ensure KeyPath only contains generic arguments and not subscript arguments (https://github.com/swiftlang/swift-foundation/issues/1482)
7876
let capturesSize = ptr.advanced(by: Self.WORD_SIZE * componentWords).load(as: UInt.self)
7977
componentWords += 2 + (Int(capturesSize) / Self.WORD_SIZE)
8078
}

Tests/FoundationEssentialsTests/PredicateTests.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,22 @@ struct PredicateTestObject2 {
3939
var a: Bool
4040
}
4141

42+
43+
fileprivate protocol PredicateProducer {
44+
var prop: Int { get }
45+
func getPredicate() -> Predicate<Self>
46+
}
47+
48+
fileprivate struct PredicateProducerConformer : PredicateProducer {
49+
let prop = 2
50+
}
51+
52+
extension PredicateProducer {
53+
func getPredicate() -> Predicate<Self> {
54+
#Predicate { $0.prop == 2 }
55+
}
56+
}
57+
4258
@Suite("Predicate")
4359
private struct PredicateTests {
4460
typealias Object = PredicateTestObject
@@ -318,6 +334,12 @@ private struct PredicateTests {
318334
_ = #Predicate<Foo> { $0.id == 2 }
319335
}
320336

337+
@Test func genericKeyPaths() {
338+
let obj = PredicateProducerConformer()
339+
// Ensure forming a predicate to a generic type does not cause crashes when validating keypaths
340+
_ = obj.getPredicate()
341+
}
342+
321343
#if FOUNDATION_EXIT_TESTS
322344
@Test func unsupportedKeyPaths() async {
323345
struct Sample {
@@ -370,12 +392,15 @@ private struct PredicateTests {
370392
}
371393

372394
// subscripts with arguments
395+
// This keypath is currently allow but should be considered invalid (https://github.com/swiftlang/swift-foundation/issues/1482)
396+
#if false
373397
await #expect(processExitsWith: .failure) {
374398
_ = PredicateExpressions.KeyPath(
375399
root: PredicateExpressions.Variable(),
376400
keyPath: \Sample.[0]
377401
)
378402
}
403+
#endif
379404

380405
// Optional chaining
381406
await #expect(processExitsWith: .failure) {

0 commit comments

Comments
 (0)