Skip to content

Commit 9acd1d9

Browse files
committed
[Diagnostics] A tailored diagnostic for Double<->CGFloat conversion via optional chaining
Implicit conversion between optional types are not currently supported, this includes optional chaining: ``` struct S { var test: CGFloat } func compute(s: Double?) -> Double? { return 42 } func test(s: S?) { _ = compute(s?.test) // CGFloat? -> Double? implicit conversion } ``` Since `S` is optional, `test` ends up optional as well and that wasn't correctly detected, so solver was allowed to form a correct solution because `CGFloat` is converted to `Double` inside of the chain _prior_ to it being wrapped into an optional because contextual type of `Double` is propagated to the result of the chain earlier that conversion takes place. Resolves: rdar://83666783
1 parent 367b4c1 commit 9acd1d9

File tree

2 files changed

+23
-0
lines changed

2 files changed

+23
-0
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5950,6 +5950,13 @@ ERROR(cannot_declare_computed_var_in_result_builder,none,
59505950
"expression shuffles the elements of this tuple; "
59515951
"this behavior is deprecated", ())
59525952

5953+
//------------------------------------------------------------------------------
5954+
// MARK: Implicit conversion diagnostics
5955+
//------------------------------------------------------------------------------
5956+
ERROR(cannot_implicitly_convert_in_optional_context,none,
5957+
"cannot implicitly convert value of type %0 to expected type %1",
5958+
(Type, Type))
5959+
59535960
//------------------------------------------------------------------------------
59545961
// MARK: marker protocol diagnostics
59555962
//------------------------------------------------------------------------------

lib/Sema/CSDiagnostics.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2418,6 +2418,22 @@ bool ContextualFailure::diagnoseAsError() {
24182418
break;
24192419
}
24202420

2421+
case ConstraintLocator::OptionalPayload: {
2422+
// If this is an attempt at a Double <-> CGFloat conversion
2423+
// through optional chaining, let's produce a tailored diagnostic.
2424+
if (isExpr<OptionalEvaluationExpr>(getAnchor())) {
2425+
if ((fromType->isDouble() || fromType->isCGFloatType()) &&
2426+
(toType->isDouble() || toType->isCGFloatType())) {
2427+
fromType = OptionalType::get(fromType);
2428+
toType = OptionalType::get(toType);
2429+
diagnostic = diag::cannot_implicitly_convert_in_optional_context;
2430+
break;
2431+
}
2432+
}
2433+
2434+
return false;
2435+
}
2436+
24212437
default:
24222438
return false;
24232439
}

0 commit comments

Comments
 (0)