Skip to content

Commit 28e69c8

Browse files
authored
Merge pull request #59762 from xedin/double-cgfloat-conv-improvements
[TypeChecker] Adjust Double<->CGFloat conversion to always preserve its location
2 parents 7b8d635 + 3fd3ff0 commit 28e69c8

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
@@ -3702,6 +3702,12 @@ class ConstraintSystem {
37023702
ConstraintLocator *
37033703
getConstraintLocator(const ConstraintLocatorBuilder &builder);
37043704

3705+
/// Compute a constraint locator for an implicit value-to-value
3706+
/// conversion rooted at the given location.
3707+
ConstraintLocator *
3708+
getImplicitValueConversionLocator(ConstraintLocatorBuilder root,
3709+
ConversionRestrictionKind restriction);
3710+
37053711
/// Lookup and return parent associated with given expression.
37063712
Expr *getParentExpr(Expr *expr) {
37073713
if (auto result = getExprDepthAndParent(expr))

lib/Sema/CSApply.cpp

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

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

67876790
solution.overloadChoices.insert({memberLoc, overload});
67886791
}
@@ -8992,15 +8995,19 @@ ExprWalker::rewriteTarget(SolutionApplicationTarget target) {
89928995
// If we're supposed to convert the expression to some particular type,
89938996
// do so now.
89948997
if (shouldCoerceToContextualType()) {
8995-
resultExpr =
8996-
Rewriter.coerceToType(resultExpr, solution.simplifyType(convertType),
8997-
cs.getConstraintLocator(resultExpr));
8998+
resultExpr = Rewriter.coerceToType(
8999+
resultExpr, solution.simplifyType(convertType),
9000+
cs.getConstraintLocator(resultExpr,
9001+
LocatorPathElt::ContextualType(
9002+
target.getExprContextualTypePurpose())));
89989003
} else if (cs.getType(resultExpr)->hasLValueType() &&
89999004
!target.isDiscardedExpr()) {
90009005
// We referenced an lvalue. Load it.
90019006
resultExpr = Rewriter.coerceToType(
90029007
resultExpr, cs.getType(resultExpr)->getRValueType(),
9003-
cs.getConstraintLocator(resultExpr));
9008+
cs.getConstraintLocator(resultExpr,
9009+
LocatorPathElt::ContextualType(
9010+
target.getExprContextualTypePurpose())));
90049011
}
90059012

90069013
if (!resultExpr)

lib/Sema/CSSimplify.cpp

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11081,9 +11081,19 @@ bool ConstraintSystem::simplifyAppliedOverloadsImpl(
1108111081
return true;
1108211082
}
1108311083

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

1108811098
// Account for any optional unwrapping/binding
1108911099
for (unsigned i : range(numOptionalUnwraps)) {
@@ -12442,28 +12452,26 @@ ConstraintSystem::simplifyRestrictedConstraintImpl(
1244212452
if (worseThanBestSolution())
1244312453
return SolutionKind::Error;
1244412454

12445-
auto *conversionLoc = getConstraintLocator(
12446-
/*anchor=*/ASTNode(), LocatorPathElt::ImplicitConversion(restriction));
12455+
auto *conversionLoc =
12456+
getImplicitValueConversionLocator(locator, restriction);
1244712457

1244812458
auto *applicationLoc =
1244912459
getConstraintLocator(conversionLoc, ConstraintLocator::ApplyFunction);
1245012460

1245112461
auto *memberLoc = getConstraintLocator(
1245212462
applicationLoc, ConstraintLocator::ConstructorMember);
1245312463

12454-
// Conversion has been already attempted for this direction
12455-
// and constructor choice has been recorded.
12456-
if (findSelectedOverloadFor(memberLoc))
12457-
return SolutionKind::Solved;
12458-
1245912464
// Allocate a single argument info to cover all possible
1246012465
// Double <-> CGFloat conversion locations.
12461-
if (!ArgumentLists.count(memberLoc)) {
12466+
auto *argumentsLoc =
12467+
getConstraintLocator(conversionLoc, ConstraintLocator::ApplyArgument);
12468+
12469+
if (!ArgumentLists.count(argumentsLoc)) {
1246212470
auto *argList = ArgumentList::createImplicit(
1246312471
getASTContext(), {Argument(SourceLoc(), Identifier(), nullptr)},
1246412472
/*firstTrailingClosureIndex=*/None,
1246512473
AllocationArena::ConstraintSolver);
12466-
ArgumentLists.insert({memberLoc, argList});
12474+
ArgumentLists.insert({argumentsLoc, argList});
1246712475
}
1246812476

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