Skip to content

Commit 599afbf

Browse files
authored
Merge pull request #60784 from xedin/rdar-99059525
[ConstraintSystem] Adjust contextual locators to support updated Double/CGFloat conversion
2 parents 6082d16 + 932c6b4 commit 599afbf

File tree

5 files changed

+84
-17
lines changed

5 files changed

+84
-17
lines changed

include/swift/Sema/ConstraintLocator.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1295,6 +1295,16 @@ class ConstraintLocatorBuilder {
12951295
return None;
12961296
}
12971297

1298+
/// Check whether this locator has the given locator path element
1299+
/// at the end of its path.
1300+
template <class Kind>
1301+
bool endsWith() const {
1302+
if (auto lastElt = last()) {
1303+
return lastElt->is<Kind>();
1304+
}
1305+
return false;
1306+
}
1307+
12981308
/// Produce a debugging dump of this locator.
12991309
SWIFT_DEBUG_DUMPER(dump(SourceManager *SM));
13001310
SWIFT_DEBUG_DUMPER(dump(ConstraintSystem *CS));

lib/Sema/CSApply.cpp

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

6795-
auto *argExpr = 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();
67966814
assert(argExpr);
67976815

67986816
// Source requires implicit conversion to match destination
@@ -8570,7 +8588,7 @@ static Optional<SolutionApplicationTarget> applySolutionToInitialization(
85708588
// Convert the initializer to the type of the pattern.
85718589
auto &cs = solution.getConstraintSystem();
85728590
auto locator = cs.getConstraintLocator(
8573-
initializer, LocatorPathElt::ContextualType(CTP_Initialization));
8591+
target.getAsExpr(), LocatorPathElt::ContextualType(CTP_Initialization));
85748592
initializer = solution.coerceToType(initializer, initType, locator);
85758593
if (!initializer)
85768594
return None;
@@ -9081,17 +9099,35 @@ ExprWalker::rewriteTarget(SolutionApplicationTarget target) {
90819099
// If we're supposed to convert the expression to some particular type,
90829100
// do so now.
90839101
if (shouldCoerceToContextualType()) {
9102+
ConstraintLocator *locator = nullptr;
9103+
9104+
auto contextualTypePurpose = target.getExprContextualTypePurpose();
9105+
// Bodies of single-expression closures use a special locator
9106+
// for contextual type conversion to make sure that result is
9107+
// convertible to `Void` when `return` is not used explicitly.
9108+
if (contextualTypePurpose == CTP_ClosureResult) {
9109+
auto *closure = cast<ClosureExpr>(target.getDeclContext());
9110+
auto *returnStmt =
9111+
castToStmt<ReturnStmt>(closure->getBody()->getLastElement());
9112+
9113+
locator = cs.getConstraintLocator(
9114+
closure, LocatorPathElt::ClosureBody(
9115+
/*hasReturn=*/!returnStmt->isImplicit()));
9116+
} else {
9117+
locator = cs.getConstraintLocator(
9118+
expr, LocatorPathElt::ContextualType(contextualTypePurpose));
9119+
}
9120+
9121+
assert(locator);
9122+
90849123
resultExpr = Rewriter.coerceToType(
9085-
resultExpr, solution.simplifyType(convertType),
9086-
cs.getConstraintLocator(resultExpr,
9087-
LocatorPathElt::ContextualType(
9088-
target.getExprContextualTypePurpose())));
9124+
resultExpr, solution.simplifyType(convertType), locator);
90899125
} else if (cs.getType(resultExpr)->hasLValueType() &&
90909126
!target.isDiscardedExpr()) {
90919127
// We referenced an lvalue. Load it.
90929128
resultExpr = Rewriter.coerceToType(
90939129
resultExpr, cs.getType(resultExpr)->getRValueType(),
9094-
cs.getConstraintLocator(resultExpr,
9130+
cs.getConstraintLocator(expr,
90959131
LocatorPathElt::ContextualType(
90969132
target.getExprContextualTypePurpose())));
90979133
}

lib/Sema/CSClosure.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1662,7 +1662,7 @@ class SyntacticElementSolutionApplication
16621662
assert(isSingleExpression);
16631663
resultTarget = SolutionApplicationTarget(
16641664
resultExpr, context.getAsDeclContext(),
1665-
mode == convertToResult ? CTP_ReturnStmt : CTP_Unused,
1665+
mode == convertToResult ? CTP_ClosureResult : CTP_Unused,
16661666
mode == convertToResult ? resultType : Type(),
16671667
/*isDiscarded=*/false);
16681668
}

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)