It's not a display issue. It's because the value passed to print is really nil. You can verify it by printing the value's type too. I think this code works as expected (it doesn't produce diagnostic) and the ?? overload called in this specific test is the one that returns non-optional value:
let x: Int? = nil
let y = (Optional(x) ?? Optional(1)) !== .some(1)
IMO it works this way:
- Compiler uses the
?? overload that returns non-optional value
Optional(x)'s type is Int?? and its value is .some(nil), so RHS of ?? is ignored.
- The result of
?? operation is nil and its type is Int?.
- As a result, both sides of
!== is Int?. The code compiles.
What's difficult to explain is the following code, which emulates the original example and produces diagnostic:
let x: Int? = nil
let y = (x ?? 1) !== .some(1)
EDIT: I figured it out. I think you're right that ??'s parameters are optional-promoted. So the code let y = (x ?? 1) !== .some(1) in the second example becomes let y = (Optional(x) ?? Optional(1)) !== .some(1) in the first example, which works as explained above. This is unexpected because I think most users (I for one) would expect compiler use the ?? overload that return optional value. Another interesting thing is that while example 1 and example 2 are equivalent because of optional promotion, compiler only produces diagnostic for example 2.
EDIT 2: to answer my own questions in my earlier post:
- Test 1: why is
flatMap closure not called?
It's because compiler chooses ?? overload that returns non-optional value. Although the original value nil (of Int? type) is promoted to .some(nil) (of Int?? type), the result of ?? operation is "downgraded" to nil (of Int? type). That's why flatMap closure isn't called.
- Test 2: why is RHS of
?? evaluated when specifying variable type explicitly?
let a: Int? = nil
let c: Int?? = a ?? 2 // c is .some(.some(2))
I believe it's because compiler chooses ?? overload that return optional value in this case.
- Test 3: why are the behaviors of using
?? and using ??? different?
It's because when using ?? compiler chooses its overload that return non-optional value, but when using ??? custom operator compiler chooses the its overload that return optional value.
Summary: It appears in all above scenarios choosing ?? overload that return optional value would greatly simplify the issue. I'll leave It to swift developers to determine if the current behavior in the original example is correct.
EDIT 3: FWIW, now that I have a better understanding of the issue, I find the first few posts actually explained it well. I'll rephrase @taylorswift's explanation and modify it a bit:
- For some reason compiler chooses the overload that returns non-optional value: (T? ?? T) -> T
flapMap requires an optional type
- From generic function's perspective T isn't an optional type, so it needs to be converted to T? somehow. The approach is to convert
(T? ?? T) -> T to (T?? ?? T?) -> T? (if compiler converts the result of the function separately, that's effectively the same as calling the overload that returns optional value).
- As part of that convertion,
T? is converted to T??, so RHS value is always .some(<value of T?>) and thus LHS is ignored.
So a verbose warning might be like this:
flatMap expects an optional type, so (T? ?? T) is converted to (T?? ?? T?), which returns a value of T?. Converting a value of T? to T?? always produces a non-nil value, so RHS of ?? is ignored.
I think it would avoid the entire issue if compiler used ?? overload that returns optional value, but it perhaps isn't worth the effort for such a corner case.