Files
swift-mirror/test/Constraints/nil-coalescing-favoring.swift
Pavel Yaskevich a01692ace1 [CSOptimizer] Skip ?? if it's involved in optional chain with unresolved result type
`??` 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
2025-11-11 15:21:33 -08:00

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)
}