Skip to content

Commit 36366bc

Browse files
committed
[Constraint solver] One SolutionApplicationTarget instance to rule them all.
Capture the peculiarities of contextual types vs. types used to generate conversion constraints, as well as the behavior of “optional some” patterns as used by if let / while let, within SolutionApplicationTarget. This allows us to use a single target throughout setup / solving / application, rather than mapping between two similar-but-disjoint targets.
1 parent 9278fb8 commit 36366bc

File tree

5 files changed

+23
-34
lines changed

5 files changed

+23
-34
lines changed

lib/Sema/CSApply.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7320,9 +7320,10 @@ Optional<SolutionApplicationTarget> ConstraintSystem::applySolution(
73207320
// We are supposed to use contextual type only if it is present and
73217321
// this expression doesn't represent the implicit return of the single
73227322
// expression function which got deduced to be `Never`.
7323-
Type convertType = target.getExprConversionType();
7323+
Type convertType = target.getExprConversionTypeForConstraint();
73247324
auto shouldCoerceToContextualType = [&]() {
73257325
return convertType &&
7326+
!target.isOptionalSomePatternInit() &&
73267327
!(getType(resultExpr)->isUninhabited() &&
73277328
getContextualTypePurpose(target.getAsExpr())
73287329
== CTP_ReturnSingleExpr);

lib/Sema/CSSolver.cpp

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1259,14 +1259,10 @@ ConstraintSystem::solveImpl(SolutionApplicationTarget &target,
12591259

12601260
// If there is a type that we're expected to convert to, add the conversion
12611261
// constraint.
1262-
if (Type convertType = target.getExprConversionType()) {
1262+
if (Type convertType = target.getExprConversionTypeForConstraint()) {
12631263
// Determine whether we know more about the contextual type.
1264-
ContextualTypePurpose ctp = CTP_Unused;
1265-
bool isOpaqueReturnType = false;
1266-
if (auto contextualInfo = getContextualTypeInfo(origExpr)) {
1267-
ctp = contextualInfo->purpose;
1268-
isOpaqueReturnType = contextualInfo->isOpaqueReturnType;
1269-
}
1264+
ContextualTypePurpose ctp = target.getExprContextualTypePurpose();
1265+
bool isOpaqueReturnType = target.infersOpaqueReturnType();
12701266

12711267
// Substitute type variables in for unresolved types.
12721268
if (allowFreeTypeVariables == FreeTypeVariableBinding::UnresolvedType) {

lib/Sema/ConstraintSystem.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4053,7 +4053,7 @@ bool SolutionApplicationTarget::contextualTypeIsOnlyAHint() const {
40534053
assert(kind == Kind::expression);
40544054
switch (expression.contextualPurpose) {
40554055
case CTP_Initialization:
4056-
return !infersOpaqueReturnType();
4056+
return !infersOpaqueReturnType() && !isOptionalSomePatternInit();
40574057
case CTP_ForEachStmt:
40584058
return true;
40594059
case CTP_Unused:

lib/Sema/ConstraintSystem.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1241,6 +1241,12 @@ class SolutionApplicationTarget {
12411241
return expression.convertType;
12421242
}
12431243

1244+
Type getExprConversionTypeForConstraint() const {
1245+
if (contextualTypeIsOnlyAHint())
1246+
return Type();
1247+
return getExprConversionType();
1248+
}
1249+
12441250
/// Returns the autoclosure parameter type, or \c nullptr if the
12451251
/// expression has a different kind of context.
12461252
FunctionType *getAsAutoclosureParamType() const {

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 11 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2107,6 +2107,7 @@ TypeChecker::typeCheckExpression(
21072107
target.setExpr(expr);
21082108
return None;
21092109
}
2110+
target.setExpr(expr);
21102111

21112112
// Construct a constraint system from this expression.
21122113
ConstraintSystemOptions csOptions = ConstraintSystemFlags::AllowFixes;
@@ -2127,46 +2128,34 @@ TypeChecker::typeCheckExpression(
21272128
// diagnostics and is a hint for various performance optimizations.
21282129
// FIXME: Look through LoadExpr. This is an egregious hack due to the
21292130
// way typeCheckExprIndependently works.
2130-
TypeLoc convertType = target.getExprConversionTypeLoc();
21312131
Expr *contextualTypeExpr = expr;
21322132
if (auto loadExpr = dyn_cast_or_null<LoadExpr>(contextualTypeExpr))
21332133
contextualTypeExpr = loadExpr->getSubExpr();
21342134
cs.setContextualType(
2135-
contextualTypeExpr, convertType,
2135+
contextualTypeExpr,
2136+
target.getExprConversionTypeLoc(),
21362137
target.getExprContextualTypePurpose(),
21372138
target.infersOpaqueReturnType());
21382139

2139-
// If the convertType is *only* provided for that hint, then null it out so
2140-
// that we don't later treat it as an actual conversion constraint.
2141-
if (target.contextualTypeIsOnlyAHint())
2142-
convertType = TypeLoc();
2143-
21442140
// If the client can handle unresolved type variables, leave them in the
21452141
// system.
21462142
auto allowFreeTypeVariables = FreeTypeVariableBinding::Disallow;
21472143
if (options.contains(TypeCheckExprFlags::AllowUnresolvedTypeVariables))
21482144
allowFreeTypeVariables = FreeTypeVariableBinding::UnresolvedType;
21492145

2150-
Type convertTo = convertType.getType();
2151-
2146+
// If the target requires an optional of some type, form a new appropriate
2147+
// type variable and update the target's type with an optional of that
2148+
// type variable.
21522149
if (target.isOptionalSomePatternInit()) {
2153-
assert(!convertTo && "convertType and type check options conflict");
2150+
assert(!target.getExprConversionType() && "convertType and type check options conflict");
21542151
auto *convertTypeLocator =
21552152
cs.getConstraintLocator(expr, LocatorPathElt::ContextualType());
21562153
Type var = cs.createTypeVariable(convertTypeLocator, TVO_CanBindToNoEscape);
2157-
convertTo = getOptionalType(expr->getLoc(), var);
2158-
} else if (target.getExprContextualTypePurpose()
2159-
== CTP_AutoclosureDefaultParameter) {
2160-
// FIXME: Hack around the convertTo adjustment below, which we want to
2161-
// eliminate.
2162-
convertTo = Type(target.getAsAutoclosureParamType());
2154+
target.setExprConversionType(getOptionalType(expr->getLoc(), var));
21632155
}
21642156

21652157
// Attempt to solve the constraint system.
2166-
SolutionApplicationTarget innerTarget(
2167-
expr, dc, target.getExprContextualTypePurpose(), convertTo,
2168-
target.isDiscardedExpr());
2169-
auto viable = cs.solve(innerTarget, listener, allowFreeTypeVariables);
2158+
auto viable = cs.solve(target, listener, allowFreeTypeVariables);
21702159
if (!viable) {
21712160
target.setExpr(expr);
21722161
return None;
@@ -2177,7 +2166,8 @@ TypeChecker::typeCheckExpression(
21772166
// because they will leak out into arbitrary places in the resultant AST.
21782167
if (options.contains(TypeCheckExprFlags::AllowUnresolvedTypeVariables) &&
21792168
(viable->size() != 1 ||
2180-
(convertType.getType() && convertType.getType()->hasUnresolvedType()))) {
2169+
(target.getExprConversionTypeForConstraint() &&
2170+
target.getExprConversionTypeForConstraint()->hasUnresolvedType()))) {
21812171
// FIXME: This hack should only be needed for CSDiag.
21822172
unresolvedTypeExprs = true;
21832173
return target;
@@ -2191,10 +2181,6 @@ TypeChecker::typeCheckExpression(
21912181
// Apply the solution to the expression.
21922182
bool performingDiagnostics =
21932183
options.contains(TypeCheckExprFlags::SubExpressionDiagnostics);
2194-
// FIXME: HACK! Copy over the inner target's expression info.
2195-
target.setExpr(innerTarget.getAsExpr());
2196-
if (convertTo.isNull())
2197-
target.setExprConversionType(convertTo);
21982184
auto resultTarget = cs.applySolution(solution, target, performingDiagnostics);
21992185
if (!resultTarget) {
22002186
// Failure already diagnosed, above, as part of applying the solution.

0 commit comments

Comments
 (0)