Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ extension PredicateCodableConfiguration {
guard root == rootReflectionType.partial, let constructed = constructor(rootReflectionType.genericArguments) else {
return nil
}
constructed._validateForPredicateUsage(restrictArguments: false)
constructed._validateForPredicateUsage()
return constructed
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ extension UInt32 {
extension AnyKeyPath {
private static var WORD_SIZE: Int { MemoryLayout<Int>.size }

func _validateForPredicateUsage(restrictArguments: Bool = true) {
func _validateForPredicateUsage() {
var ptr = unsafeBitCast(self, to: UnsafeRawPointer.self)
ptr = ptr.advanced(by: Self.WORD_SIZE * 3) // skip isa, type metadata, and KVC string pointers
let header = ptr.load(as: UInt32.self)
Expand All @@ -72,9 +72,7 @@ extension AnyKeyPath {
componentWords += 1
}
if firstComponentHeader._keyPathComponentHeader_computedHasArguments {
if restrictArguments {
fatalError("Predicate does not support keypaths with arguments")
}
// TODO: Ensure KeyPath only contains generic arguments and not subscript arguments (https://github.com/swiftlang/swift-foundation/issues/1482)
let capturesSize = ptr.advanced(by: Self.WORD_SIZE * componentWords).load(as: UInt.self)
componentWords += 2 + (Int(capturesSize) / Self.WORD_SIZE)
}
Expand Down
25 changes: 25 additions & 0 deletions Tests/FoundationEssentialsTests/PredicateTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,22 @@ struct PredicateTestObject2 {
var a: Bool
}


fileprivate protocol PredicateProducer {
var prop: Int { get }
func getPredicate() -> Predicate<Self>
}

fileprivate struct PredicateProducerConformer : PredicateProducer {
let prop = 2
}

extension PredicateProducer {
func getPredicate() -> Predicate<Self> {
#Predicate { $0.prop == 2 }
}
}

@Suite("Predicate")
private struct PredicateTests {
typealias Object = PredicateTestObject
Expand Down Expand Up @@ -318,6 +334,12 @@ private struct PredicateTests {
_ = #Predicate<Foo> { $0.id == 2 }
}

@Test func genericKeyPaths() {
let obj = PredicateProducerConformer()
// Ensure forming a predicate to a generic type does not cause crashes when validating keypaths
_ = obj.getPredicate()
}

#if FOUNDATION_EXIT_TESTS
@Test func unsupportedKeyPaths() async {
struct Sample {
Expand Down Expand Up @@ -370,12 +392,15 @@ private struct PredicateTests {
}

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

// Optional chaining
await #expect(processExitsWith: .failure) {
Expand Down