Skip to content

Commit ef926f8

Browse files
authored
Merge pull request #59784 from xedin/double-cgfloat-conv-improvements-5.7
[5.7][TypeChecker] Adjust Double<->CGFloat conversion to always preserve its location
2 parents bc0eb2e + 7777e3a commit ef926f8

File tree

6 files changed

+107
-33
lines changed

6 files changed

+107
-33
lines changed

include/swift/Sema/ConstraintSystem.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3658,6 +3658,12 @@ class ConstraintSystem {
36583658
ConstraintLocator *
36593659
getConstraintLocator(const ConstraintLocatorBuilder &builder);
36603660

3661+
/// Compute a constraint locator for an implicit value-to-value
3662+
/// conversion rooted at the given location.
3663+
ConstraintLocator *
3664+
getImplicitValueConversionLocator(ConstraintLocatorBuilder root,
3665+
ConversionRestrictionKind restriction);
3666+
36613667
/// Lookup and return parent associated with given expression.
36623668
Expr *getParentExpr(Expr *expr) {
36633669
if (auto result = getExprDepthAndParent(expr))

lib/Sema/CSApply.cpp

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6782,10 +6782,13 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
67826782
callLocator, {ConstraintLocator::ApplyFunction,
67836783
ConstraintLocator::ConstructorMember});
67846784

6785-
auto overload = solution.getOverloadChoice(cs.getConstraintLocator(
6786-
ASTNode(), {LocatorPathElt::ImplicitConversion(conversionKind),
6787-
ConstraintLocator::ApplyFunction,
6788-
ConstraintLocator::ConstructorMember}));
6785+
ConstraintLocator *baseLoc =
6786+
cs.getImplicitValueConversionLocator(locator, conversionKind);
6787+
6788+
auto overload =
6789+
solution.getOverloadChoice(solution.getConstraintLocator(
6790+
baseLoc, {ConstraintLocator::ApplyFunction,
6791+
ConstraintLocator::ConstructorMember}));
67896792

67906793
solution.overloadChoices.insert({memberLoc, overload});
67916794
}
@@ -8990,15 +8993,19 @@ ExprWalker::rewriteTarget(SolutionApplicationTarget target) {
89908993
// If we're supposed to convert the expression to some particular type,
89918994
// do so now.
89928995
if (shouldCoerceToContextualType()) {
8993-
resultExpr =
8994-
Rewriter.coerceToType(resultExpr, solution.simplifyType(convertType),
8995-
cs.getConstraintLocator(resultExpr));
8996+
resultExpr = Rewriter.coerceToType(
8997+
resultExpr, solution.simplifyType(convertType),
8998+
cs.getConstraintLocator(resultExpr,
8999+
LocatorPathElt::ContextualType(
9000+
target.getExprContextualTypePurpose())));
89969001
} else if (cs.getType(resultExpr)->hasLValueType() &&
89979002
!target.isDiscardedExpr()) {
89989003
// We referenced an lvalue. Load it.
89999004
resultExpr = Rewriter.coerceToType(
90009005
resultExpr, cs.getType(resultExpr)->getRValueType(),
9001-
cs.getConstraintLocator(resultExpr));
9006+
cs.getConstraintLocator(resultExpr,
9007+
LocatorPathElt::ContextualType(
9008+
target.getExprContextualTypePurpose())));
90029009
}
90039010

90049011
if (!resultExpr)

lib/Sema/CSSimplify.cpp

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11084,9 +11084,19 @@ bool ConstraintSystem::simplifyAppliedOverloadsImpl(
1108411084
return true;
1108511085
}
1108611086

11087-
// If types lined up exactly, let's favor this overload choice.
11088-
if (Type(argFnType)->isEqual(choiceType))
11089-
constraint->setFavored();
11087+
// If types of arguments/parameters and result lined up exactly,
11088+
// let's favor this overload choice.
11089+
//
11090+
// Note this check ignores `ExtInfo` on purpose and only compares
11091+
// types, if there are overloads that differ only in effects then
11092+
// all of them are going to be considered and filtered as part of
11093+
// "favored" group after forming a valid partial solution.
11094+
if (auto *choiceFnType = choiceType->getAs<FunctionType>()) {
11095+
if (FunctionType::equalParams(argFnType->getParams(),
11096+
choiceFnType->getParams()) &&
11097+
argFnType->getResult()->isEqual(choiceFnType->getResult()))
11098+
constraint->setFavored();
11099+
}
1109011100

1109111101
// Account for any optional unwrapping/binding
1109211102
for (unsigned i : range(numOptionalUnwraps)) {
@@ -12445,28 +12455,26 @@ ConstraintSystem::simplifyRestrictedConstraintImpl(
1244512455
if (worseThanBestSolution())
1244612456
return SolutionKind::Error;
1244712457

12448-
auto *conversionLoc = getConstraintLocator(
12449-
/*anchor=*/ASTNode(), LocatorPathElt::ImplicitConversion(restriction));
12458+
auto *conversionLoc =
12459+
getImplicitValueConversionLocator(locator, restriction);
1245012460

1245112461
auto *applicationLoc =
1245212462
getConstraintLocator(conversionLoc, ConstraintLocator::ApplyFunction);
1245312463

1245412464
auto *memberLoc = getConstraintLocator(
1245512465
applicationLoc, ConstraintLocator::ConstructorMember);
1245612466

12457-
// Conversion has been already attempted for this direction
12458-
// and constructor choice has been recorded.
12459-
if (findSelectedOverloadFor(memberLoc))
12460-
return SolutionKind::Solved;
12461-
1246212467
// Allocate a single argument info to cover all possible
1246312468
// Double <-> CGFloat conversion locations.
12464-
if (!ArgumentLists.count(memberLoc)) {
12469+
auto *argumentsLoc =
12470+
getConstraintLocator(conversionLoc, ConstraintLocator::ApplyArgument);
12471+
12472+
if (!ArgumentLists.count(argumentsLoc)) {
1246512473
auto *argList = ArgumentList::createImplicit(
1246612474
getASTContext(), {Argument(SourceLoc(), Identifier(), nullptr)},
1246712475
/*firstTrailingClosureIndex=*/None,
1246812476
AllocationArena::ConstraintSolver);
12469-
ArgumentLists.insert({memberLoc, argList});
12477+
ArgumentLists.insert({argumentsLoc, argList});
1247012478
}
1247112479

1247212480
auto *memberTypeLoc = getConstraintLocator(

lib/Sema/ConstraintSystem.cpp

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -424,21 +424,43 @@ ConstraintLocator *ConstraintSystem::getConstraintLocator(
424424
return getConstraintLocator(anchor, newPath);
425425
}
426426

427+
ConstraintLocator *ConstraintSystem::getImplicitValueConversionLocator(
428+
ConstraintLocatorBuilder root, ConversionRestrictionKind restriction) {
429+
SmallVector<LocatorPathElt, 4> path;
430+
auto anchor = root.getLocatorParts(path);
431+
{
432+
// Drop any value-to-optional conversions that were applied along the
433+
// way to reach this one.
434+
while (!path.empty()) {
435+
if (path.back().is<LocatorPathElt::OptionalPayload>()) {
436+
path.pop_back();
437+
continue;
438+
}
439+
break;
440+
}
441+
442+
// If the conversion is associated with a contextual type e.g.
443+
// `_: Double = CGFloat(1)` then drop `ContextualType` so that
444+
// it's easy to find when the underlying expression has been
445+
// rewritten.
446+
if (!path.empty() && path.back().is<LocatorPathElt::ContextualType>()) {
447+
anchor = ASTNode();
448+
path.clear();
449+
}
450+
}
451+
452+
return getConstraintLocator(/*base=*/getConstraintLocator(anchor, path),
453+
LocatorPathElt::ImplicitConversion(restriction));
454+
}
455+
427456
ConstraintLocator *ConstraintSystem::getCalleeLocator(
428457
ConstraintLocator *locator, bool lookThroughApply,
429458
llvm::function_ref<Type(Expr *)> getType,
430459
llvm::function_ref<Type(Type)> simplifyType,
431460
llvm::function_ref<Optional<SelectedOverload>(ConstraintLocator *)>
432461
getOverloadFor) {
433-
if (auto conversion =
434-
locator->findLast<LocatorPathElt::ImplicitConversion>()) {
435-
if (conversion->is(ConversionRestrictionKind::DoubleToCGFloat) ||
436-
conversion->is(ConversionRestrictionKind::CGFloatToDouble)) {
437-
return getConstraintLocator(
438-
ASTNode(), {*conversion, ConstraintLocator::ApplyFunction,
439-
ConstraintLocator::ConstructorMember});
440-
}
441-
}
462+
if (locator->findLast<LocatorPathElt::ImplicitConversion>())
463+
return locator;
442464

443465
auto anchor = locator->getAnchor();
444466
auto path = locator->getPath();
@@ -5323,6 +5345,9 @@ ConstraintSystem::getArgumentInfoLocator(ConstraintLocator *locator) {
53235345
if (anchor.isNull() && locator->getPath().empty())
53245346
return nullptr;
53255347

5348+
if (locator->findLast<LocatorPathElt::ImplicitConversion>())
5349+
return locator;
5350+
53265351
// Applies and unresolved member exprs can have callee locators that are
53275352
// dependent on the type of their function, which may not have been resolved
53285353
// yet. Therefore we need to handle them specially.

test/Constraints/implicit_double_cgfloat_conversion.swift

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -194,18 +194,25 @@ func test_no_ambiguity_with_unary_operators(width: CGFloat, height: CGFloat) {
194194
}
195195

196196
func test_conversions_with_optional_promotion(d: Double, cgf: CGFloat) {
197-
func test_double(_: Double??) {}
198-
func test_cgfloat(_: CGFloat??) {}
197+
func test_double(_: Double??, _: Double???) {}
198+
func test_cgfloat(_: CGFloat??, _: CGFloat???) {}
199199

200200
// CHECK: function_ref @$sSd12CoreGraphicsEySdAA7CGFloatVcfC
201201
// CHECK-NEXT: apply
202202
// CHECK-NEXT: enum $Optional<Double>, #Optional.some!enumelt
203203
// CHECK-NEXT: enum $Optional<Optional<Double>>, #Optional.some!enumelt
204-
test_double(cgf)
204+
test_double(cgf, cgf)
205205

206206
// CHECK: function_ref @$s12CoreGraphics7CGFloatVyACSdcfC
207207
// CHECK-NEXT: apply
208208
// CHECK-NEXT: enum $Optional<CGFloat>, #Optional.some!enumelt
209209
// CHECK-NEXT: enum $Optional<Optional<CGFloat>>, #Optional.some!enumelt
210-
test_cgfloat(d)
210+
test_cgfloat(d, d)
211+
}
212+
213+
// https://github.com/apple/swift/issues/59374
214+
func test_multi_argument_conversion_with_optional(d: Double, cgf: CGFloat) {
215+
func test(_: Double, _: CGFloat?) {}
216+
217+
test(cgf, d) // Ok (CGFloat -> Double and Double? -> CGFloat?)
211218
}

test/Constraints/overload_filtering_objc.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,24 @@ func testOptional(obj: P) {
2222
// CHECK: [disabled] $T2 bound to decl overload_filtering_objc.(file).P.opt(double:)
2323
_ = obj.opt?(1)
2424
}
25+
26+
27+
func test_double_cgfloat_conversion_filtering(d: Double, cgf: CGFloat) {
28+
// CHECK: [favored] $T{{.*}} bound to decl CoreGraphics.(file).CGFloat.init(_:)@{{.*}} : (CGFloat.Type) -> (Double) -> CGFloat {{.*}} -> implicit conversion [Double-to-CGFloat] -> apply function -> constructor member
29+
let _: CGFloat = d
30+
31+
// CHECK: [favored] $T{{.*}} bound to decl CoreGraphics.(file).Double extension.init(_:)@{{.*}} : (Double.Type) -> (CGFloat) -> Double {{.*}} -> implicit conversion [CGFloat-to-Double] -> apply function -> constructor member
32+
let _: Double = cgf
33+
34+
func test_optional_cgf(_: CGFloat??) {
35+
}
36+
37+
func test_optional_double(_: Double??) {
38+
}
39+
40+
// CHECK: [favored] $T{{.*}} bound to decl CoreGraphics.(file).CGFloat.init(_:)@{{.*}} : (CGFloat.Type) -> (Double) -> CGFloat {{.*}} -> implicit conversion [Double-to-CGFloat] -> apply function -> constructor member
41+
test_optional_cgf(d)
42+
43+
// CHECK: [favored] $T{{.*}} bound to decl CoreGraphics.(file).Double extension.init(_:)@{{.*}} : (Double.Type) -> (CGFloat) -> Double {{.*}} -> implicit conversion [CGFloat-to-Double] -> apply function -> constructor member
44+
test_optional_double(cgf)
45+
}

0 commit comments

Comments
 (0)