Skip to content

Commit 932c6b4

Browse files
committed
[ConstraintSystem] Don't use special locator for value-to-value conversions related to contextual type
Previously locator for value-to-value conversion would just drop all the contextual information if the conversion occurred while converting expression to a contextual type. This is incorrect for i.e. `return` statements and other targets because because they are solved separately and using the same locator would result in a clash when solutions are merged.
1 parent b23f1c2 commit 932c6b4

File tree

3 files changed

+55
-20
lines changed

3 files changed

+55
-20
lines changed

lib/Sema/CSApply.cpp

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6792,12 +6792,25 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
67926792
case ConversionRestrictionKind::DoubleToCGFloat: {
67936793
auto conversionKind = knownRestriction->second;
67946794

6795-
// If conversion wraps the whole body of a single-expression closure,
6796-
// let's use the passed-in expression since the closure itself doesn't
6797-
// get updated until coercion is done.
6798-
auto *argExpr = locator.endsWith<LocatorPathElt::ClosureBody>()
6799-
? expr
6800-
: locator.trySimplifyToExpr();
6795+
auto shouldUseCoercedExpr = [&]() {
6796+
// If conversion wraps the whole body of a single-expression closure,
6797+
// let's use the passed-in expression since the closure itself doesn't
6798+
// get updated until coercion is done.
6799+
if (locator.endsWith<LocatorPathElt::ClosureBody>())
6800+
return true;
6801+
6802+
// Contextual type locator always uses the original version of
6803+
// expression (before any coercions have been applied) because
6804+
// otherwise it wouldn't be possible to find the overload choice.
6805+
if (locator.endsWith<LocatorPathElt::ContextualType>())
6806+
return true;
6807+
6808+
// In all other cases use the expression associated with locator.
6809+
return false;
6810+
};
6811+
6812+
auto *argExpr =
6813+
shouldUseCoercedExpr() ? expr : locator.trySimplifyToExpr();
68016814
assert(argExpr);
68026815

68036816
// Source requires implicit conversion to match destination
@@ -8575,7 +8588,7 @@ static Optional<SolutionApplicationTarget> applySolutionToInitialization(
85758588
// Convert the initializer to the type of the pattern.
85768589
auto &cs = solution.getConstraintSystem();
85778590
auto locator = cs.getConstraintLocator(
8578-
initializer, LocatorPathElt::ContextualType(CTP_Initialization));
8591+
target.getAsExpr(), LocatorPathElt::ContextualType(CTP_Initialization));
85798592
initializer = solution.coerceToType(initializer, initType, locator);
85808593
if (!initializer)
85818594
return None;
@@ -9087,10 +9100,12 @@ ExprWalker::rewriteTarget(SolutionApplicationTarget target) {
90879100
// do so now.
90889101
if (shouldCoerceToContextualType()) {
90899102
ConstraintLocator *locator = nullptr;
9103+
9104+
auto contextualTypePurpose = target.getExprContextualTypePurpose();
90909105
// Bodies of single-expression closures use a special locator
90919106
// for contextual type conversion to make sure that result is
90929107
// convertible to `Void` when `return` is not used explicitly.
9093-
if (target.getExprContextualTypePurpose() == CTP_ClosureResult) {
9108+
if (contextualTypePurpose == CTP_ClosureResult) {
90949109
auto *closure = cast<ClosureExpr>(target.getDeclContext());
90959110
auto *returnStmt =
90969111
castToStmt<ReturnStmt>(closure->getBody()->getLastElement());
@@ -9100,8 +9115,7 @@ ExprWalker::rewriteTarget(SolutionApplicationTarget target) {
91009115
/*hasReturn=*/!returnStmt->isImplicit()));
91019116
} else {
91029117
locator = cs.getConstraintLocator(
9103-
resultExpr, LocatorPathElt::ContextualType(
9104-
target.getExprContextualTypePurpose()));
9118+
expr, LocatorPathElt::ContextualType(contextualTypePurpose));
91059119
}
91069120

91079121
assert(locator);
@@ -9113,7 +9127,7 @@ ExprWalker::rewriteTarget(SolutionApplicationTarget target) {
91139127
// We referenced an lvalue. Load it.
91149128
resultExpr = Rewriter.coerceToType(
91159129
resultExpr, cs.getType(resultExpr)->getRValueType(),
9116-
cs.getConstraintLocator(resultExpr,
9130+
cs.getConstraintLocator(expr,
91179131
LocatorPathElt::ContextualType(
91189132
target.getExprContextualTypePurpose())));
91199133
}

lib/Sema/ConstraintSystem.cpp

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -444,15 +444,6 @@ ConstraintLocator *ConstraintSystem::getImplicitValueConversionLocator(
444444
break;
445445
}
446446

447-
// If the conversion is associated with a contextual type e.g.
448-
// `_: Double = CGFloat(1)` then drop `ContextualType` so that
449-
// it's easy to find when the underlying expression has been
450-
// rewritten.
451-
if (!path.empty() && path.back().is<LocatorPathElt::ContextualType>()) {
452-
anchor = ASTNode();
453-
path.clear();
454-
}
455-
456447
// If conversion is for a tuple element, let's drop `TupleType`
457448
// components from the path since they carry information for
458449
// diagnostics that `ExprRewriter` won't be able to re-construct

test/Constraints/implicit_double_cgfloat_conversion.swift

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,3 +285,33 @@ func test_conversion_inside_tuple_elements() -> (a: CGFloat, b: (c: Int, d: CGFl
285285
let x: Double = 0.0
286286
return (a: x, b: (c: 42, d: x)) // Ok
287287
}
288+
289+
do {
290+
struct Data {
291+
var prop: CGFloat
292+
}
293+
294+
func single(get: () -> Double) {}
295+
func multiple(get1: () -> Double,
296+
get2: () -> CGFloat = { Double(1) },
297+
get3: () -> Double) {}
298+
299+
func test(data: Data) {
300+
single { data.prop } // Ok
301+
single { return data.prop } // Ok
302+
303+
single {
304+
_ = 42
305+
if true {
306+
return data.prop // Ok
307+
}
308+
return data.prop // Ok
309+
}
310+
311+
multiple {
312+
data.prop // Ok
313+
} get3: {
314+
return data.prop // Ok
315+
}
316+
}
317+
}

0 commit comments

Comments
 (0)