Skip to content

Commit 510c0b8

Browse files
committed
Add Optional/Result: Equatable where Element: ~Copyable
1 parent 07bd46f commit 510c0b8

File tree

5 files changed

+83
-13
lines changed

5 files changed

+83
-13
lines changed

stdlib/public/core/Optional.swift

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -522,7 +522,8 @@ func _diagnoseUnexpectedNilOptional(
522522
}
523523
}
524524

525-
extension Optional: Equatable where Wrapped: Equatable {
525+
@_preInverseGenerics
526+
extension Optional: Equatable where Wrapped: Equatable & ~Copyable {
526527
/// Returns a Boolean value indicating whether two optional instances are
527528
/// equal.
528529
///
@@ -568,14 +569,19 @@ extension Optional: Equatable where Wrapped: Equatable {
568569
/// - lhs: An optional value to compare.
569570
/// - rhs: Another optional value to compare.
570571
@_transparent
571-
public static func ==(lhs: Wrapped?, rhs: Wrapped?) -> Bool {
572-
switch (lhs, rhs) {
573-
case let (l?, r?):
574-
return l == r
575-
case (nil, nil):
576-
return true
577-
default:
578-
return false
572+
@_preInverseGenerics
573+
public static func ==(lhs: borrowing Wrapped?, rhs: borrowing Wrapped?) -> Bool {
574+
switch lhs {
575+
case let l?:
576+
switch rhs {
577+
case let r?: l == r
578+
case nil: false
579+
}
580+
case nil:
581+
switch rhs {
582+
case _?: false
583+
case nil: true
584+
}
579585
}
580586
}
581587
}

stdlib/public/core/Result.swift

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,24 @@ extension Result: Escapable where Success: Escapable & ~Copyable {}
2727

2828
extension Result: Sendable where Success: Sendable & ~Copyable & ~Escapable {}
2929

30-
extension Result: Equatable where Success: Equatable, Failure: Equatable {}
30+
@_preInverseGenerics
31+
extension Result: Equatable where Success: Equatable & ~Copyable, Failure: Equatable {
32+
@_preInverseGenerics
33+
public static func ==(lhs: borrowing Self, rhs: borrowing Self) -> Bool {
34+
switch lhs {
35+
case let .success(l):
36+
switch rhs {
37+
case let .success(r): l == r
38+
case .failure: false
39+
}
40+
case let .failure(l):
41+
switch rhs {
42+
case .success: false
43+
case let .failure(r): l == r
44+
}
45+
}
46+
}
47+
}
3148

3249
extension Result: Hashable where Success: Hashable, Failure: Hashable {}
3350

test/api-digester/Outputs/stability-stdlib-source-base.swift.expected

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,10 +270,14 @@ Func Optional.!=(_:_:) has generic signature change from <Wrapped> to <Wrapped w
270270
Func Optional.!=(_:_:) has parameter 0 changing from Default to Shared
271271
Func Optional.!=(_:_:) has parameter 1 changing from Default to Shared
272272
Func Optional.==(_:_:) has generic signature change from <Wrapped> to <Wrapped where Wrapped : ~Copyable, Wrapped : ~Escapable>
273+
Func Optional.==(_:_:) has generic signature change from <Wrapped where Wrapped : Swift.Equatable> to <Wrapped where Wrapped : Swift.Equatable, Wrapped : ~Copyable>
273274
Func Optional.==(_:_:) has parameter 0 changing from Default to Shared
274275
Func Optional.==(_:_:) has parameter 1 changing from Default to Shared
275276
Func Optional.~=(_:_:) has generic signature change from <Wrapped> to <Wrapped where Wrapped : ~Copyable, Wrapped : ~Escapable>
276277
Func Optional.~=(_:_:) has parameter 1 changing from Default to Shared
278+
Func Result.==(_:_:) has generic signature change from <Success, Failure where Success : Swift.Equatable, Failure : Swift.Equatable, Failure : Swift.Error> to <Success, Failure where Success : Swift.Equatable, Failure : Swift.Equatable, Failure : Swift.Error, Success : ~Copyable>
279+
Func Result.==(_:_:) has parameter 0 changing from Default to Shared
280+
Func Result.==(_:_:) has parameter 1 changing from Default to Shared
277281
Func Result.get() has generic signature change from <Success, Failure where Failure : Swift.Error> to <Success, Failure where Failure : Swift.Error, Success : ~Copyable, Success : ~Escapable>
278282
Func Result.get() has self access kind changing from NonMutating to Consuming
279283
Func Result.mapError(_:) has self access kind changing from NonMutating to Consuming

test/api-digester/stability-stdlib-abi-without-asserts.test

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,7 +611,9 @@ Func Optional.!=(_:_:) has mangled name changing from 'static Swift.Optional.!=
611611
Func Optional.!=(_:_:) has parameter 0 changing from Default to Shared
612612
Func Optional.!=(_:_:) has parameter 1 changing from Default to Shared
613613
Func Optional.!=(_:_:) is now with @_preInverseGenerics
614+
Func Optional.==(_:_:) has generic signature change from <Wrapped where Wrapped : Swift.Equatable> to <Wrapped where Wrapped : Swift.Equatable, Wrapped : ~Copyable>
614615
Func Optional.==(_:_:) has generic signature change from <Wrapped> to <Wrapped where Wrapped : ~Copyable, Wrapped : ~Escapable>
616+
Func Optional.==(_:_:) has mangled name changing from 'static (extension in Swift):Swift.Optional<A where A: Swift.Equatable>.== infix(Swift.Optional<A>, Swift.Optional<A>) -> Swift.Bool' to 'static (extension in Swift):Swift.Optional< where A: Swift.Equatable, A: ~Swift.Copyable>.== infix(Swift.Optional<A>, Swift.Optional<A>) -> Swift.Bool'
615617
Func Optional.==(_:_:) has mangled name changing from 'static Swift.Optional.== infix(Swift.Optional<A>, Swift._OptionalNilComparisonType) -> Swift.Bool' to 'static (extension in Swift):Swift.Optional< where A: ~Swift.Copyable, A: ~Swift.Escapable>.== infix(Swift.Optional<A>, Swift._OptionalNilComparisonType) -> Swift.Bool'
616618
Func Optional.==(_:_:) has mangled name changing from 'static Swift.Optional.== infix(Swift._OptionalNilComparisonType, Swift.Optional<A>) -> Swift.Bool' to 'static (extension in Swift):Swift.Optional< where A: ~Swift.Copyable, A: ~Swift.Escapable>.== infix(Swift._OptionalNilComparisonType, Swift.Optional<A>) -> Swift.Bool'
617619
Func Optional.==(_:_:) has parameter 0 changing from Default to Shared
@@ -623,6 +625,11 @@ Func Optional.~=(_:_:) has parameter 1 changing from Default to Shared
623625
Func Optional.~=(_:_:) is now with @_preInverseGenerics
624626
Func Result.get() has been removed
625627
Func Result.mapError(_:) has been removed
628+
Func Result.==(_:_:) has generic signature change from <Success, Failure where Success : Swift.Equatable, Failure : Swift.Equatable, Failure : Swift.Error> to <Success, Failure where Success : Swift.Equatable, Failure : Swift.Equatable, Failure : Swift.Error, Success : ~Copyable>
629+
Func Result.==(_:_:) has mangled name changing from 'static (extension in Swift):Swift.Result< where A: Swift.Equatable, B: Swift.Equatable>.== infix(Swift.Result<A, B>, Swift.Result<A, B>) -> Swift.Bool' to 'static (extension in Swift):Swift.Result< where A: Swift.Equatable, B: Swift.Equatable, A: ~Swift.Copyable>.== infix(Swift.Result<A, B>, Swift.Result<A, B>) -> Swift.Bool'
630+
Func Result.==(_:_:) has parameter 0 changing from Default to Shared
631+
Func Result.==(_:_:) has parameter 1 changing from Default to Shared
632+
Func Result.==(_:_:) is now with @_preInverseGenerics
626633
Func TextOutputStreamable.write(to:) has generic signature change from <Self, Target where Self : Swift.TextOutputStreamable, Target : Swift.TextOutputStream> to <Self, Target where Self : Swift.TextOutputStreamable, Target : Swift.TextOutputStream, Self : ~Copyable>
627634
Func UnsafeBufferPointer.deallocate() has generic signature change from <Element> to <Element where Element : ~Copyable>
628635
Func UnsafeBufferPointer.deallocate() has mangled name changing from 'Swift.UnsafeBufferPointer.deallocate() -> ()' to '(extension in Swift):Swift.UnsafeBufferPointer< where A: ~Swift.Copyable>.deallocate() -> ()'

test/stdlib/NoncopyableEquatable.swift

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ NoncopyableEquatableTests.test("comparing noncopyables") {
7171
expectTrue(array.minIndex() == 2)
7272
}
7373

74-
extension Noncopyable: CustomStringConvertible {
74+
extension Noncopyable: CustomStringConvertible {
7575
var description: String {
7676
"No copying the number \(i)"
7777
}
@@ -100,12 +100,48 @@ func debug(value: borrowing some CustomDebugStringConvertible & ~Copyable) -> St
100100
value.debugDescription
101101
}
102102

103-
NoncopyableEquatableTests.test("noncopyable interpolation") {
103+
NoncopyableEquatableTests.test("noncopyable interpolation") {
104104

105105
let a = Noncopyable(riskily: "99")
106106

107107
expectEqual("NC: \(a)", "NC: No copying the number \(a.i)")
108108
expectEqual("Noncopyable(i: \(a.i))", debug(value: a))
109-
}
109+
}
110+
111+
NoncopyableEquatableTests.test("equating optional noncopyables") {
112+
let o1: Noncopyable? = Noncopyable(i: 1)
113+
let o2: Noncopyable = .init(i: 1)
114+
expectTrue(o1 == consume o2)
115+
}
116+
117+
118+
extension Noncopyable {
119+
struct Nope: Error, Equatable { let s: String }
120+
121+
init(throws from: String) throws(Nope) {
122+
guard let i = Int(from) else { throw Nope(s: from) }
123+
self = .init(i: i)
124+
}
125+
}
126+
127+
NoncopyableEquatableTests.test("equating optional noncopyables") {
128+
let o1: Noncopyable? = Noncopyable(i: 1)
129+
let o2: Noncopyable = .init(i: 1)
130+
expectTrue(o1 == consume o2)
131+
}
132+
133+
NoncopyableEquatableTests.test("noncopyable result") {
134+
let r = Result { () throws(Noncopyable.Nope) -> Noncopyable in
135+
try Noncopyable(throws: "99")
136+
}
137+
expectTrue(r == .success(.init(i: 99)))
138+
139+
let n = Result { () throws(Noncopyable.Nope) -> Noncopyable in try Noncopyable(throws: "nope") }
140+
expectTrue(r != n)
141+
let m = Result { () throws(Noncopyable.Nope) -> Noncopyable in try Noncopyable(throws: "nope") }
142+
expectTrue(n == m)
143+
144+
expectEqual(try! r.get().i, 99)
145+
}
110146

111147
runAllTests()

0 commit comments

Comments
 (0)