[CSSimplify] CGFloat-Double: Rank narrowing correctly when result is injected into an optional

If result of `CGFloat` -> `Double` conversion is injected into an optional
it should be ranked based on depth just like when locator is fully simplified.

For example:

```swift
func test(v: CGFloat?) {
   _ = v ?? 2.0 / 3.0
}
```

In this expression division should be performed on `Double` and result
narrowed down (based on the rule that narrowing conversion should always
be delayed) but `Double` -> `CGFloat?` was given an incorrect score and
instead of picking `?? (_: T?, _: T) -> T` overload, the solver would
use `?? (_: T?, _: T?) -> T?`.

(cherry picked from commit cb876cbd9e)
This commit is contained in:
Pavel Yaskevich
2024-11-25 20:30:04 -08:00
parent f650c0ac6e
commit 69bd48e2ea
2 changed files with 15 additions and 6 deletions

View File

@@ -15184,9 +15184,19 @@ ConstraintSystem::simplifyRestrictedConstraintImpl(
restriction == ConversionRestrictionKind::CGFloatToDouble ? 2 : 10;
if (restriction == ConversionRestrictionKind::DoubleToCGFloat) {
if (auto *anchor = locator.trySimplifyToExpr()) {
if (auto depth = getExprDepth(anchor))
impact = (*depth + 1) * impact;
SmallVector<LocatorPathElt> originalPath;
auto anchor = locator.getLocatorParts(originalPath);
SourceRange range;
ArrayRef<LocatorPathElt> path(originalPath);
simplifyLocator(anchor, path, range);
if (path.empty() || llvm::all_of(path, [](const LocatorPathElt &elt) {
return elt.is<LocatorPathElt::OptionalInjection>();
})) {
if (auto *expr = getAsExpr(anchor))
if (auto depth = getExprDepth(expr))
impact = (*depth + 1) * impact;
}
} else if (locator.directlyAt<AssignExpr>() ||
locator.endsWith<LocatorPathElt::ContextualType>()) {

View File

@@ -6,7 +6,7 @@ import CoreGraphics
/////////////
struct G<T> { // expected-note {{arguments to generic parameter 'T' ('CGFloat?' and 'CGFloat') are expected to be equal}}
struct G<T> {
var t: T
}
@@ -32,8 +32,7 @@ func foo4(x: (() -> ())?, y: @escaping @convention(block) () -> ()) -> G<() -> (
func foo5(x: CGFloat?, y: Double) -> G<CGFloat> {
let g = G(t: x ?? y)
// FIXME
return g // expected-error {{cannot convert return expression of type 'G<CGFloat?>' to return type 'G<CGFloat>'}}
return g
}
func foo6(x: Double?, y: CGFloat) -> G<Double> {