mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
`??` operator is overloaded on optionality of its result. When the first argument matches exactly, the ranking is going to be skewed towards selecting an overload choice that returns a non-optional type. This is not always correct i.e. when operator is involved in optional chaining. To avoid producing an incorrect favoring, let's skip the this disjunction when constraints associated with result type indicate that it should be optional. Simply adding it as a binding won't work because if the second argument is non-optional the overload that returns `T?` would still have a lower score. Resolves: rdar://164201746
74 lines
2.0 KiB
Swift
74 lines
2.0 KiB
Swift
// RUN: %target-swift-frontend -dump-ast %s | %FileCheck %s
|
|
|
|
struct B {
|
|
static var _none: B { B() }
|
|
}
|
|
|
|
struct A {
|
|
init(_ other: B) {}
|
|
// CHECK: constructor_decl{{.*}}interface_type="(A.Type) -> (B?) -> A"
|
|
init(_ other: B?) {
|
|
// CHECK: dot_syntax_call_expr type="(B) -> A"
|
|
self.init(other ?? ._none)
|
|
}
|
|
}
|
|
|
|
do {
|
|
class Super {}
|
|
class Sub: Super {}
|
|
|
|
func flatMap<R>(_: (Int) -> R?) -> R? {}
|
|
|
|
func test() {
|
|
let dict: Dictionary<Int, Sub>
|
|
let sup: Super
|
|
|
|
// CHECK: declref_expr type="(consuming Super?, @autoclosure () throws -> Super) throws -> Super" {{.*}} decl="Swift.(file).??
|
|
let x = flatMap { dict[$0] } ?? sup // Ok
|
|
let _: Super = x
|
|
}
|
|
}
|
|
|
|
// Reduced from vapor project. Favoring _only_ an overload of `??` and takes `T?` as a second parameter would result in an invalid solution.
|
|
extension Array where Element == UInt8 {
|
|
init?(decodingBase32 str: String) {
|
|
guard let decoded = str.utf8.withContiguousStorageIfAvailable({ Array(decodingBase32: $0) }) ?? Array(decodingBase32: Array(str.utf8)) else { // Ok
|
|
return nil
|
|
}
|
|
self = decoded
|
|
}
|
|
|
|
init?<C>(decodingBase32 bytes: C) where C: RandomAccessCollection, C.Element == UInt8, C.Index == Int {
|
|
fatalError()
|
|
}
|
|
}
|
|
|
|
func test_no_incorrect_favoring(v: Int?, o: Int) {
|
|
func ternary<T>(_: T, _: T) -> T { fatalError() }
|
|
|
|
func nilCoelesing<T>(_: T?, _: T) -> T { fatalError() }
|
|
func nilCoelesing<T>(_: T?, _: T?) -> T? { fatalError() }
|
|
|
|
let t1 = v ?? (true ? nil : v)
|
|
let t2 = v ?? ternary(nil, o)
|
|
|
|
let s1 = nilCoelesing(v, (true ? nil : v))
|
|
let s2 = nilCoelesing(v, ternary(nil, o))
|
|
|
|
func sameType<T>(_: T, as: T.Type) {}
|
|
|
|
sameType(t1, as: Int?.self)
|
|
sameType(t2, as: Int?.self)
|
|
sameType(s1, as: Int?.self)
|
|
sameType(s2, as: Int?.self)
|
|
}
|
|
|
|
extension Int {
|
|
func test() -> Int { 42 }
|
|
}
|
|
|
|
func test_optional_chaining(v: Int?, defaultV: Int) {
|
|
// CHECK: declref_expr type="(consuming Int?, @autoclosure () throws -> Int?) throws -> Int?" {{.*}} decl="Swift.(file).??
|
|
_ = (v ?? defaultV)?.test() // Ok (no warnings)
|
|
}
|