Skip to content
Draft
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
21 changes: 12 additions & 9 deletions stdlib/public/core/Comparable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@
/// (`FloatingPoint.nan`) compares as neither less than, greater than, nor
/// equal to any normal floating-point value. Exceptional values need not
/// take part in the strict total order.
public protocol Comparable: Equatable {
public protocol Comparable: Equatable, ~Copyable {
/// Returns a Boolean value indicating whether the value of the first
/// argument is less than that of the second argument.
///
Expand All @@ -146,34 +146,34 @@ public protocol Comparable: Equatable {
/// - Parameters:
/// - lhs: A value to compare.
/// - rhs: Another value to compare.
static func < (lhs: Self, rhs: Self) -> Bool
static func < (lhs: borrowing Self, rhs: borrowing Self) -> Bool

/// Returns a Boolean value indicating whether the value of the first
/// argument is less than or equal to that of the second argument.
///
/// - Parameters:
/// - lhs: A value to compare.
/// - rhs: Another value to compare.
static func <= (lhs: Self, rhs: Self) -> Bool
static func <= (lhs: borrowing Self, rhs: borrowing Self) -> Bool

/// Returns a Boolean value indicating whether the value of the first
/// argument is greater than or equal to that of the second argument.
///
/// - Parameters:
/// - lhs: A value to compare.
/// - rhs: Another value to compare.
static func >= (lhs: Self, rhs: Self) -> Bool
static func >= (lhs: borrowing Self, rhs: borrowing Self) -> Bool

/// Returns a Boolean value indicating whether the value of the first
/// argument is greater than that of the second argument.
///
/// - Parameters:
/// - lhs: A value to compare.
/// - rhs: Another value to compare.
static func > (lhs: Self, rhs: Self) -> Bool
static func > (lhs: borrowing Self, rhs: borrowing Self) -> Bool
}

extension Comparable {
extension Comparable where Self: ~Copyable {
/// Returns a Boolean value indicating whether the value of the first argument
/// is greater than that of the second argument.
///
Expand All @@ -184,7 +184,8 @@ extension Comparable {
/// - lhs: A value to compare.
/// - rhs: Another value to compare.
@inlinable
public static func > (lhs: Self, rhs: Self) -> Bool {
@_preInverseGenerics
public static func > (lhs: borrowing Self, rhs: borrowing Self) -> Bool {
return rhs < lhs
}

Expand All @@ -198,7 +199,8 @@ extension Comparable {
/// - lhs: A value to compare.
/// - rhs: Another value to compare.
@inlinable
public static func <= (lhs: Self, rhs: Self) -> Bool {
@_preInverseGenerics
public static func <= (lhs: borrowing Self, rhs: borrowing Self) -> Bool {
return !(rhs < lhs)
}

Expand All @@ -214,7 +216,8 @@ extension Comparable {
/// - Returns: `true` if `lhs` is greater than or equal to `rhs`; otherwise,
/// `false`.
@inlinable
public static func >= (lhs: Self, rhs: Self) -> Bool {
@_preInverseGenerics
public static func >= (lhs: borrowing Self, rhs: borrowing Self) -> Bool {
return !(lhs < rhs)
}
}
9 changes: 5 additions & 4 deletions stdlib/public/core/Equatable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@
/// let c = a
/// print(c === a, c === b, separator: ", ")
/// // Prints "true, false"
public protocol Equatable {
public protocol Equatable: ~Copyable {
/// Returns a Boolean value indicating whether two values are equal.
///
/// Equality is the inverse of inequality. For any values `a` and `b`,
Expand All @@ -173,10 +173,10 @@ public protocol Equatable {
/// - Parameters:
/// - lhs: A value to compare.
/// - rhs: Another value to compare.
static func == (lhs: Self, rhs: Self) -> Bool
static func == (lhs: borrowing Self, rhs: borrowing Self) -> Bool
}

extension Equatable {
extension Equatable where Self: ~Copyable {
/// Returns a Boolean value indicating whether two values are not equal.
///
/// Inequality is the inverse of equality. For any values `a` and `b`, `a != b`
Expand All @@ -190,8 +190,9 @@ extension Equatable {
/// - rhs: Another value to compare.
// transparent because sometimes types that use this generate compile-time
// warnings, e.g. that an expression always evaluates to true
@_preInverseGenerics
@_transparent
public static func != (lhs: Self, rhs: Self) -> Bool {
public static func != (lhs: borrowing Self, rhs: borrowing Self) -> Bool {
return !(lhs == rhs)
}
}
Expand Down
24 changes: 15 additions & 9 deletions stdlib/public/core/Optional.swift
Original file line number Diff line number Diff line change
Expand Up @@ -522,7 +522,8 @@ func _diagnoseUnexpectedNilOptional(
}
}

extension Optional: Equatable where Wrapped: Equatable {
@_preInverseGenerics
extension Optional: Equatable where Wrapped: Equatable & ~Copyable {
/// Returns a Boolean value indicating whether two optional instances are
/// equal.
///
Expand Down Expand Up @@ -568,14 +569,19 @@ extension Optional: Equatable where Wrapped: Equatable {
/// - lhs: An optional value to compare.
/// - rhs: Another optional value to compare.
@_transparent
public static func ==(lhs: Wrapped?, rhs: Wrapped?) -> Bool {
switch (lhs, rhs) {
case let (l?, r?):
return l == r
case (nil, nil):
return true
default:
return false
@_preInverseGenerics
public static func ==(lhs: borrowing Wrapped?, rhs: borrowing Wrapped?) -> Bool {
switch lhs {
case let l?:
switch rhs {
case let r?: l == r
case nil: false
}
case nil:
switch rhs {
case _?: false
case nil: true
}
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions stdlib/public/core/OutputStream.swift
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ extension TextOutputStream {
/// To add `TextOutputStreamable` conformance to a custom type, implement the
/// required `write(to:)` method. Call the given output stream's `write(_:)`
/// method in your implementation.
public protocol TextOutputStreamable {
public protocol TextOutputStreamable: ~Copyable {
/// Writes a textual representation of this instance into the given output
/// stream.
func write<Target: TextOutputStream>(to target: inout Target)
Expand Down Expand Up @@ -147,7 +147,7 @@ public protocol TextOutputStreamable {
///
/// print(p)
/// // Prints "(21, 30)"
public protocol CustomStringConvertible {
public protocol CustomStringConvertible: ~Copyable {
/// A textual representation of this instance.
///
/// Calling this property directly is discouraged. Instead, convert an
Expand Down Expand Up @@ -182,7 +182,7 @@ public protocol CustomStringConvertible {
/// The description property of a conforming type must be a value-preserving
/// representation of the original value. As such, it should be possible to
/// re-create an instance from its string representation.
public protocol LosslessStringConvertible: CustomStringConvertible {
public protocol LosslessStringConvertible: CustomStringConvertible, ~Copyable {
/// Instantiates an instance of the conforming type from a string
/// representation.
init?(_ description: String)
Expand Down Expand Up @@ -239,7 +239,7 @@ public protocol LosslessStringConvertible: CustomStringConvertible {
///
/// print(String(reflecting: p))
/// // Prints "(21, 30)"
public protocol CustomDebugStringConvertible {
public protocol CustomDebugStringConvertible: ~Copyable {
/// A textual representation of this instance, suitable for debugging.
///
/// Calling this property directly is discouraged. Instead, convert an
Expand Down
19 changes: 18 additions & 1 deletion stdlib/public/core/Result.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,24 @@ extension Result: Escapable where Success: Escapable & ~Copyable {}

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

extension Result: Equatable where Success: Equatable, Failure: Equatable {}
@_preInverseGenerics
extension Result: Equatable where Success: Equatable & ~Copyable, Failure: Equatable {
@_preInverseGenerics
public static func ==(lhs: borrowing Self, rhs: borrowing Self) -> Bool {
switch lhs {
case let .success(l):
switch rhs {
case let .success(r): l == r
case .failure: false
}
case let .failure(l):
switch rhs {
case .success: false
case let .failure(r): l == r
}
}
}
}

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

Expand Down
52 changes: 31 additions & 21 deletions stdlib/public/core/StringInterpolation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,9 @@ public struct DefaultStringInterpolation: StringInterpolationProtocol, Sendable
/// print(message)
/// // Prints "If one cookie costs 2 dollars, 3 cookies cost 6 dollars."
@inlinable
public mutating func appendInterpolation<T>(_ value: T)
where T: TextOutputStreamable, T: CustomStringConvertible
@_preInverseGenerics
public mutating func appendInterpolation<T>(_ value: borrowing T)
where T: TextOutputStreamable, T: CustomStringConvertible, T: ~Copyable
{
value.write(to: &self)
}
Expand All @@ -127,8 +128,9 @@ public struct DefaultStringInterpolation: StringInterpolationProtocol, Sendable
/// print(message)
/// // Prints "If one cookie costs 2 dollars, 3 cookies cost 6 dollars."
@inlinable
public mutating func appendInterpolation<T>(_ value: T)
where T: TextOutputStreamable
@_preInverseGenerics
public mutating func appendInterpolation<T>(_ value: borrowing T)
where T: TextOutputStreamable & ~Copyable
{
value.write(to: &self)
}
Expand All @@ -151,8 +153,9 @@ public struct DefaultStringInterpolation: StringInterpolationProtocol, Sendable
/// print(message)
/// // Prints "If one cookie costs 2 dollars, 3 cookies cost 6 dollars."
@inlinable
public mutating func appendInterpolation<T>(_ value: T)
where T: CustomStringConvertible
@_preInverseGenerics
public mutating func appendInterpolation<T>(_ value: borrowing T)
where T: CustomStringConvertible, T: ~Copyable
{
value.description.write(to: &self)
}
Expand All @@ -175,7 +178,7 @@ public struct DefaultStringInterpolation: StringInterpolationProtocol, Sendable
/// print(message)
/// // Prints "If one cookie costs 2 dollars, 3 cookies cost 6 dollars."
@inlinable
public mutating func appendInterpolation<T>(_ value: T) {
public mutating func appendInterpolation<T>(_ value: borrowing T) {
#if !$Embedded
_print_unlocked(value, &self)
#else
Expand Down Expand Up @@ -217,13 +220,15 @@ extension DefaultStringInterpolation {
/// - value: The value to include in a string interpolation, if non-`nil`.
/// - default: The string to include if `value` is `nil`.
@_alwaysEmitIntoClient
@_preInverseGenerics
public mutating func appendInterpolation<T>(
_ value: T?,
_ value: borrowing T?,
default: @autoclosure () -> some StringProtocol
) where T: TextOutputStreamable, T: CustomStringConvertible {
if let value {
) where T: TextOutputStreamable, T: CustomStringConvertible, T: ~Copyable {
switch value {
case let value?:
self.appendInterpolation(value)
} else {
case nil:
self.appendInterpolation(`default`())
}
}
Expand All @@ -247,13 +252,15 @@ extension DefaultStringInterpolation {
/// - value: The value to include in a string interpolation, if non-`nil`.
/// - default: The string to include if `value` is `nil`.
@_alwaysEmitIntoClient
@_preInverseGenerics
public mutating func appendInterpolation<T>(
_ value: T?,
_ value: borrowing T?,
default: @autoclosure () -> some StringProtocol
) where T: TextOutputStreamable {
if let value {
) where T: TextOutputStreamable & ~Copyable {
switch value {
case let value?:
self.appendInterpolation(value)
} else {
case nil:
self.appendInterpolation(`default`())
}
}
Expand All @@ -277,13 +284,15 @@ extension DefaultStringInterpolation {
/// - value: The value to include in a string interpolation, if non-`nil`.
/// - default: The string to include if `value` is `nil`.
@_alwaysEmitIntoClient
@_preInverseGenerics
public mutating func appendInterpolation<T>(
_ value: T?,
_ value: borrowing T?,
default: @autoclosure () -> some StringProtocol
) where T: CustomStringConvertible {
if let value {
) where T: CustomStringConvertible, T: ~Copyable {
switch value {
case let value?:
self.appendInterpolation(value)
} else {
case nil:
self.appendInterpolation(`default`())
}
}
Expand Down Expand Up @@ -311,9 +320,10 @@ extension DefaultStringInterpolation {
_ value: T?,
default: @autoclosure () -> some StringProtocol
) {
if let value {
switch value {
case let value?:
self.appendInterpolation(value)
} else {
case nil:
self.appendInterpolation(`default`())
}
}
Expand Down
2 changes: 1 addition & 1 deletion test/Concurrency/member_operator_adjustment.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

// CHECK: (func_decl decl_context={{.*}} range={{.*}} "test(v:)"
func test<T: Equatable>(v: T) {
// CHECK: (function_conversion_expr implicit type="@Sendable (T.Type) -> (T, T) -> Bool"
// CHECK: (function_conversion_expr implicit type="@Sendable (T.Type) -> (borrowing T, borrowing T) -> Bool"
_ = v == v
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,5 @@ func test(arr: [any P]) {
// CHECK: sil private [ossa] @$s34anyhashable_and_operator_filtering4test3arrySayAA1P_pG_tFyAaD_pXEfU_
// CHECK: [[LHS_ARG:%.*]] = alloc_stack $E
// CHECK: [[RHS_ARG:%.*]] = alloc_stack $E
// CHECK: [[GENERIC_OP:%.*]] = witness_method $E, #Equatable."==" : <Self where Self : Equatable> (Self.Type) -> (Self, Self) -> Bool
// CHECK: [[GENERIC_OP:%.*]] = witness_method $E, #Equatable."==" : <Self where Self : Equatable, Self : ~Copyable> (Self.Type) -> (borrowing Self, borrowing Self) -> Bool
// CHECK-NEXT: apply [[GENERIC_OP]]<E>([[LHS_ARG]], [[RHS_ARG]], {{.*}})
15 changes: 6 additions & 9 deletions test/Constraints/diagnostics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1470,14 +1470,12 @@ func testUnwrapFixIts(x: Int?) throws {
// expected-note@-2 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{11-11=!}}
foo(y: x ?? 0)

let _ = x < 2 // expected-error {{value of optional type 'Int?' must be unwrapped to a value of type 'Int'}}
// expected-note@-1 {{coalesce using '??' to provide a default when the optional value contains 'nil'}} {{12-12= ?? <#default value#>}}
// expected-note@-2 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{12-12=!}}
let _ = x < 2 // expected-error {{binary operator '<' cannot be applied to operands of type 'Int?' and 'Int'}}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like there's some dedicated diagnostic that we're no longer getting here, but I'm not sure how much value it was adding to begin with.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah tbh I feel like the newer diagnostic is better

// expected-note@-1 {{overloads for '<' exist with these partially matching parameter lists: (Int, Int)}}
let _ = x ?? 0 < 2

let _ = 2 < x // expected-error {{value of optional type 'Int?' must be unwrapped to a value of type 'Int'}}
// expected-note@-1 {{coalesce using '??' to provide a default when the optional value contains 'nil'}} {{16-16= ?? <#default value#>}}
// expected-note@-2 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{16-16=!}}
let _ = 2 < x // expected-error {{binary operator '<' cannot be applied to operands of type 'Int' and 'Int?'}}
// expected-note@-1 {{overloads for '<' exist with these partially matching parameter lists: (Int, Int)}}
let _ = 2 < x ?? 0

let _: Int = (.optionalIntMember) // expected-error {{value of optional type 'Int?' must be unwrapped to a value of type 'Int'}}
Expand All @@ -1495,9 +1493,8 @@ func testUnwrapFixIts(x: Int?) throws {
// expected-note@-2 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{36-36=!}}
let _ = try (.optionalThrowsMember ?? 0) + 1

let _ = .optionalIntMember?.bitWidth > 0 // expected-error {{value of optional type 'Int?' must be unwrapped to a value of type 'Int'}}
// expected-note@-1 {{coalesce using '??' to provide a default when the optional value contains 'nil'}} {{39-39= ?? <#default value#>}}
// expected-note@-2 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} {{11-11=(}} {{39-39=)!}}
let _ = .optionalIntMember?.bitWidth > 0 // expected-error {{binary operator '>' cannot be applied to operands of type 'Int?' and 'Int'}}
// expected-note@-1 {{overloads for '>' exist with these partially matching parameter lists: (Int, Int)}}
let _ = (.optionalIntMember?.bitWidth)! > 0
let _ = .optionalIntMember?.bitWidth ?? 0 > 0

Expand Down
2 changes: 1 addition & 1 deletion test/Constraints/rdar158063151.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ struct Value: Equatable, ExpressibleByNilLiteral {
}

// CHECK-LABEL: sil hidden [ossa] @$s13rdar1580631514test1vyAA5ValueV_tF : $@convention(thin) (Value) -> ()
// CHECK: [[EQUALS_REF:%.*]] = witness_method $Value, #Equatable."==" : <Self where Self : Equatable> (Self.Type) -> (Self, Self) -> Bool
// CHECK: [[EQUALS_REF:%.*]] = witness_method $Value, #Equatable."==" : <Self where Self : Equatable, Self : ~Copyable> (Self.Type) -> (borrowing Self, borrowing Self) -> Bool
// CHECK-NEXT: apply [[EQUALS_REF]]<Value>({{.*}})
func test(v: Value) {
_ = v == nil
Expand Down
2 changes: 1 addition & 1 deletion test/Generics/inverse_copyable_requirement.swift
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ func checkCasting(_ b: any Box, _ mo: borrowing MO, _ a: Any) {
// the stdlib right now is not yet being compiled with NoncopyableGenerics
func checkStdlibTypes(_ mo: borrowing MO) {
_ = "\(mo)" // expected-error {{no exact matches in call to instance method 'appendInterpolation'}}
let _: String = String(describing: mo) // expected-error {{no exact matches in call to initializer}}
let _: String = String(describing: mo) // expected-error {{initializer 'init(describing:)' requires that 'MO' conform to 'Copyable'}}

let _: [MO] = // expected-error {{type 'MO' does not conform to protocol 'Copyable'}}
[MO(), MO()]
Expand Down
Loading