Skip to content

Commit efd357e

Browse files
committed
[Constraint system] Factor out application to a SolutionApplicationTarget.
Pull out the core operation of rewriting a given SolutionApplicationTarget into into a method on the ExprWalker that does the overall rewrite, so it can be called multiple times within application.
1 parent a308a7e commit efd357e

File tree

2 files changed

+89
-71
lines changed

2 files changed

+89
-71
lines changed

lib/Sema/CSApply.cpp

Lines changed: 88 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ namespace {
290290
public:
291291
ConstraintSystem &cs;
292292
DeclContext *dc;
293-
const Solution &solution;
293+
Solution &solution;
294294
bool SuppressDiagnostics;
295295

296296
/// Coerce the given tuple to another tuple type.
@@ -1792,7 +1792,7 @@ namespace {
17921792
}
17931793

17941794
public:
1795-
ExprRewriter(ConstraintSystem &cs, const Solution &solution,
1795+
ExprRewriter(ConstraintSystem &cs, Solution &solution,
17961796
bool suppressDiagnostics)
17971797
: cs(cs), dc(cs.DC), solution(solution),
17981798
SuppressDiagnostics(suppressDiagnostics) {}
@@ -7142,6 +7142,10 @@ namespace {
71427142

71437143
/// Ignore declarations.
71447144
bool walkToDeclPre(Decl *decl) override { return false; }
7145+
7146+
/// Rewrite the target, producing a new target.
7147+
Optional<SolutionApplicationTarget>
7148+
rewriteTarget(SolutionApplicationTarget target);
71457149
};
71467150
} // end anonymous namespace
71477151

@@ -7305,41 +7309,14 @@ static Optional<SolutionApplicationTarget> applySolutionToInitialization(
73057309
return resultTarget;
73067310
}
73077311

7308-
/// Apply a given solution to the expression, producing a fully
7309-
/// type-checked expression.
7310-
Optional<SolutionApplicationTarget> ConstraintSystem::applySolution(
7311-
Solution &solution, SolutionApplicationTarget target,
7312-
bool performingDiagnostics) {
7313-
// If any fixes needed to be applied to arrive at this solution, resolve
7314-
// them to specific expressions.
7315-
if (!solution.Fixes.empty()) {
7316-
if (shouldSuppressDiagnostics())
7317-
return None;
7318-
7319-
bool diagnosedErrorsViaFixes = applySolutionFixes(solution);
7320-
// If all of the available fixes would result in a warning,
7321-
// we can go ahead and apply this solution to AST.
7322-
if (!llvm::all_of(solution.Fixes, [](const ConstraintFix *fix) {
7323-
return fix->isWarning();
7324-
})) {
7325-
// If we already diagnosed any errors via fixes, that's it.
7326-
if (diagnosedErrorsViaFixes)
7327-
return None;
7328-
7329-
// If we didn't manage to diagnose anything well, so fall back to
7330-
// diagnosing mining the system to construct a reasonable error message.
7331-
diagnoseFailureFor(target);
7332-
return None;
7333-
}
7334-
}
7335-
7336-
ExprRewriter rewriter(*this, solution, shouldSuppressDiagnostics());
7337-
ExprWalker walker(rewriter);
7312+
Optional<SolutionApplicationTarget>
7313+
ExprWalker::rewriteTarget(SolutionApplicationTarget target) {
7314+
auto &solution = Rewriter.solution;
73387315

73397316
// Apply the solution to the target.
73407317
SolutionApplicationTarget result = target;
73417318
if (auto expr = target.getAsExpr()) {
7342-
Expr *rewrittenExpr = expr->walk(walker);
7319+
Expr *rewrittenExpr = expr->walk(*this);
73437320
if (!rewrittenExpr)
73447321
return None;
73457322

@@ -7358,19 +7335,19 @@ Optional<SolutionApplicationTarget> ConstraintSystem::applySolution(
73587335
auto fn = *target.getAsFunction();
73597336

73607337
// Dig out the function builder transformation we applied.
7361-
auto transform = rewriter.getAppliedBuilderTransform(fn);
7338+
auto transform = Rewriter.getAppliedBuilderTransform(fn);
73627339
assert(transform);
73637340

73647341
auto newBody = applyFunctionBuilderTransform(
73657342
solution, *transform, fn.getBody(), fn.getAsDeclContext(),
73667343
[&](Expr *expr) {
7367-
Expr *result = expr->walk(walker);
7344+
Expr *result = expr->walk(*this);
73687345
if (result)
73697346
solution.setExprTypes(result);
73707347
return result;
73717348
},
73727349
[&](Expr *expr, Type toType, ConstraintLocator *locator) {
7373-
return rewriter.coerceToType(expr, toType, locator);
7350+
return Rewriter.coerceToType(expr, toType, locator);
73747351
});
73757352

73767353
if (!newBody)
@@ -7379,26 +7356,8 @@ Optional<SolutionApplicationTarget> ConstraintSystem::applySolution(
73797356
result.setFunctionBody(newBody);
73807357
}
73817358

7382-
// If we're re-typechecking an expression for diagnostics, don't
7383-
// visit closures that have non-single expression bodies.
7384-
if (!performingDiagnostics) {
7385-
bool hadError = false;
7386-
for (auto *closure : walker.getClosuresToTypeCheck())
7387-
hadError |= TypeChecker::typeCheckClosureBody(closure);
7388-
7389-
// Tap expressions too; they should or should not be
7390-
// type-checked under the same conditions as closure bodies.
7391-
for (auto tuple : walker.getTapsToTypeCheck()) {
7392-
auto tap = std::get<0>(tuple);
7393-
auto tapDC = std::get<1>(tuple);
7394-
hadError |= TypeChecker::typeCheckTapBody(tap, tapDC);
7395-
}
7396-
7397-
// If any of them failed to type check, bail.
7398-
if (hadError)
7399-
return None;
7400-
}
7401-
7359+
// Follow-up tasks.
7360+
auto &cs = solution.getConstraintSystem();
74027361
if (auto resultExpr = result.getAsExpr()) {
74037362
Expr *expr = target.getAsExpr();
74047363
assert(expr && "Can't have expression result without expression target");
@@ -7410,23 +7369,24 @@ Optional<SolutionApplicationTarget> ConstraintSystem::applySolution(
74107369
auto shouldCoerceToContextualType = [&]() {
74117370
return convertType &&
74127371
!target.isOptionalSomePatternInit() &&
7413-
!(getType(resultExpr)->isUninhabited() &&
7414-
getContextualTypePurpose(target.getAsExpr())
7372+
!(solution.getType(resultExpr)->isUninhabited() &&
7373+
cs.getContextualTypePurpose(target.getAsExpr())
74157374
== CTP_ReturnSingleExpr);
74167375
};
74177376

74187377
// If we're supposed to convert the expression to some particular type,
74197378
// do so now.
74207379
if (shouldCoerceToContextualType()) {
7421-
resultExpr = rewriter.coerceToType(resultExpr,
7422-
simplifyType(convertType),
7423-
getConstraintLocator(expr));
7424-
} else if (getType(resultExpr)->hasLValueType() &&
7380+
resultExpr = Rewriter.coerceToType(resultExpr,
7381+
solution.simplifyType(convertType),
7382+
cs.getConstraintLocator(expr));
7383+
} else if (cs.getType(resultExpr)->hasLValueType() &&
74257384
!target.isDiscardedExpr()) {
74267385
// We referenced an lvalue. Load it.
7427-
resultExpr = rewriter.coerceToType(resultExpr,
7428-
getType(resultExpr)->getRValueType(),
7429-
getConstraintLocator(expr));
7386+
resultExpr = Rewriter.coerceToType(
7387+
resultExpr,
7388+
cs.getType(resultExpr)->getRValueType(),
7389+
cs.getConstraintLocator(expr));
74307390
}
74317391

74327392
if (!resultExpr)
@@ -7436,28 +7396,86 @@ Optional<SolutionApplicationTarget> ConstraintSystem::applySolution(
74367396
// conversion.
74377397
if (FunctionType *autoclosureParamType =
74387398
target.getAsAutoclosureParamType()) {
7439-
resultExpr = buildAutoClosureExpr(resultExpr, autoclosureParamType);
7399+
resultExpr = cs.buildAutoClosureExpr(resultExpr, autoclosureParamType);
74407400
}
74417401

74427402
solution.setExprTypes(resultExpr);
74437403
result.setExpr(resultExpr);
74447404

7445-
if (Context.TypeCheckerOpts.DebugConstraintSolver) {
7446-
auto &log = Context.TypeCheckerDebug->getStream();
7405+
auto &ctx = cs.getASTContext();
7406+
if (ctx.TypeCheckerOpts.DebugConstraintSolver) {
7407+
auto &log = ctx.TypeCheckerDebug->getStream();
74477408
log << "---Type-checked expression---\n";
74487409
resultExpr->dump(log);
74497410
log << "\n";
74507411
}
74517412
}
74527413

7414+
return result;
7415+
}
7416+
7417+
/// Apply a given solution to the expression, producing a fully
7418+
/// type-checked expression.
7419+
Optional<SolutionApplicationTarget> ConstraintSystem::applySolution(
7420+
Solution &solution, SolutionApplicationTarget target,
7421+
bool performingDiagnostics) {
7422+
// If any fixes needed to be applied to arrive at this solution, resolve
7423+
// them to specific expressions.
7424+
if (!solution.Fixes.empty()) {
7425+
if (shouldSuppressDiagnostics())
7426+
return None;
7427+
7428+
bool diagnosedErrorsViaFixes = applySolutionFixes(solution);
7429+
// If all of the available fixes would result in a warning,
7430+
// we can go ahead and apply this solution to AST.
7431+
if (!llvm::all_of(solution.Fixes, [](const ConstraintFix *fix) {
7432+
return fix->isWarning();
7433+
})) {
7434+
// If we already diagnosed any errors via fixes, that's it.
7435+
if (diagnosedErrorsViaFixes)
7436+
return None;
7437+
7438+
// If we didn't manage to diagnose anything well, so fall back to
7439+
// diagnosing mining the system to construct a reasonable error message.
7440+
diagnoseFailureFor(target);
7441+
return None;
7442+
}
7443+
}
7444+
7445+
ExprRewriter rewriter(*this, solution, shouldSuppressDiagnostics());
7446+
ExprWalker walker(rewriter);
7447+
auto resultTarget = walker.rewriteTarget(target);
7448+
if (!resultTarget)
7449+
return None;
7450+
7451+
// If we're re-typechecking an expression for diagnostics, don't
7452+
// visit closures that have non-single expression bodies.
7453+
if (!performingDiagnostics) {
7454+
bool hadError = false;
7455+
for (auto *closure : walker.getClosuresToTypeCheck())
7456+
hadError |= TypeChecker::typeCheckClosureBody(closure);
7457+
7458+
// Tap expressions too; they should or should not be
7459+
// type-checked under the same conditions as closure bodies.
7460+
for (auto tuple : walker.getTapsToTypeCheck()) {
7461+
auto tap = std::get<0>(tuple);
7462+
auto tapDC = std::get<1>(tuple);
7463+
hadError |= TypeChecker::typeCheckTapBody(tap, tapDC);
7464+
}
7465+
7466+
// If any of them failed to type check, bail.
7467+
if (hadError)
7468+
return None;
7469+
}
7470+
74537471
rewriter.finalize();
74547472

7455-
return result;
7473+
return resultTarget;
74567474
}
74577475

74587476
Expr *Solution::coerceToType(Expr *expr, Type toType,
74597477
ConstraintLocator *locator,
7460-
Optional<Pattern*> typeFromPattern) const {
7478+
Optional<Pattern*> typeFromPattern) {
74617479
auto &cs = getConstraintSystem();
74627480
ExprRewriter rewriter(cs, *this, /*suppressDiagnostics=*/false);
74637481
Expr *result = rewriter.coerceToType(expr, toType, locator, typeFromPattern);

lib/Sema/ConstraintSystem.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -886,7 +886,7 @@ class Solution {
886886
/// \returns the coerced expression, which will have type \c ToType.
887887
Expr *coerceToType(Expr *expr, Type toType,
888888
ConstraintLocator *locator,
889-
Optional<Pattern*> typeFromPattern = None) const;
889+
Optional<Pattern*> typeFromPattern = None);
890890

891891
/// Compute the set of substitutions for a generic signature opened at the
892892
/// given locator.

0 commit comments

Comments
 (0)