Skip to content

Commit d4cd5e0

Browse files
authored
Merge pull request swiftlang#29801 from DougGregor/constraint-solver-rewrite-target
[Constraint system] Factor out application to a SolutionApplicationTarget
2 parents 6c7cdef + 7f90290 commit d4cd5e0

File tree

3 files changed

+141
-108
lines changed

3 files changed

+141
-108
lines changed

lib/Sema/BuilderTransform.cpp

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -627,8 +627,9 @@ class BuilderClosureRewriter
627627
const Solution &solution;
628628
DeclContext *dc;
629629
AppliedBuilderTransform builderTransform;
630-
std::function<Expr *(Expr *)> rewriteExpr;
631-
std::function<Expr *(Expr *, Type, ConstraintLocator *)> coerceToType;
630+
std::function<
631+
Optional<SolutionApplicationTarget> (SolutionApplicationTarget)>
632+
rewriteTarget;
632633

633634
/// Retrieve the temporary variable that will be used to capture the
634635
/// value of the given expression.
@@ -648,6 +649,17 @@ class BuilderClosureRewriter
648649
return recorded;
649650
}
650651

652+
/// Rewrite an expression without any particularly special context.
653+
Expr *rewriteExpr(Expr *expr) {
654+
auto result = rewriteTarget(
655+
SolutionApplicationTarget(expr, dc, CTP_Unused, Type(),
656+
/*isDiscarded=*/false));
657+
if (result)
658+
return result->getAsExpr();
659+
660+
return nullptr;
661+
}
662+
651663
public:
652664
/// Retrieve information about a captured statement.
653665
std::pair<VarDecl *, llvm::TinyPtrVector<Expr *>>
@@ -673,19 +685,21 @@ class BuilderClosureRewriter
673685
ASTNode initializeTarget(FunctionBuilderTarget target) {
674686
assert(target.captured.second.size() == 1);
675687
auto capturedExpr = target.captured.second.front();
676-
auto finalCapturedExpr = rewriteExpr(capturedExpr);
677688
SourceLoc implicitLoc = capturedExpr->getEndLoc();
678689
switch (target.kind) {
679690
case FunctionBuilderTarget::ReturnValue: {
680691
// Return the expression.
681-
ConstraintSystem &cs = solution.getConstraintSystem();
682692
Type bodyResultType =
683693
solution.simplifyType(builderTransform.bodyResultType);
684-
finalCapturedExpr = coerceToType(
685-
finalCapturedExpr,
686-
bodyResultType,
687-
cs.getConstraintLocator(capturedExpr));
688-
return new (ctx) ReturnStmt(implicitLoc, finalCapturedExpr);
694+
695+
SolutionApplicationTarget returnTarget(
696+
capturedExpr, dc, CTP_ReturnStmt, bodyResultType,
697+
/*isDiscarded=*/false);
698+
Expr *resultExpr = nullptr;
699+
if (auto resultTarget = rewriteTarget(returnTarget))
700+
resultExpr = resultTarget->getAsExpr();
701+
702+
return new (ctx) ReturnStmt(implicitLoc, resultExpr);
689703
}
690704

691705
case FunctionBuilderTarget::TemporaryVar: {
@@ -696,6 +710,7 @@ class BuilderClosureRewriter
696710
declRef->setType(LValueType::get(temporaryVar->getType()));
697711

698712
// Load the right-hand side if needed.
713+
auto finalCapturedExpr = rewriteExpr(capturedExpr);
699714
if (finalCapturedExpr->getType()->hasLValueType()) {
700715
finalCapturedExpr =
701716
TypeChecker::addImplicitLoadExpr(ctx, finalCapturedExpr);
@@ -734,12 +749,12 @@ class BuilderClosureRewriter
734749
const Solution &solution,
735750
DeclContext *dc,
736751
const AppliedBuilderTransform &builderTransform,
737-
std::function<Expr *(Expr *)> rewriteExpr,
738-
std::function<Expr *(Expr *, Type, ConstraintLocator *)> coerceToType
752+
std::function<
753+
Optional<SolutionApplicationTarget> (SolutionApplicationTarget)>
754+
rewriteTarget
739755
) : ctx(solution.getConstraintSystem().getASTContext()),
740756
solution(solution), dc(dc), builderTransform(builderTransform),
741-
rewriteExpr(rewriteExpr),
742-
coerceToType(coerceToType){ }
757+
rewriteTarget(rewriteTarget) { }
743758

744759
Stmt *visitBraceStmt(BraceStmt *braceStmt, FunctionBuilderTarget target,
745760
Optional<FunctionBuilderTarget> innerTarget = None) {
@@ -954,9 +969,10 @@ BraceStmt *swift::applyFunctionBuilderTransform(
954969
AppliedBuilderTransform applied,
955970
BraceStmt *body,
956971
DeclContext *dc,
957-
std::function<Expr *(Expr *)> rewriteExpr,
958-
std::function<Expr *(Expr *, Type, ConstraintLocator *)> coerceToType) {
959-
BuilderClosureRewriter rewriter(solution, dc, applied, rewriteExpr, coerceToType);
972+
std::function<
973+
Optional<SolutionApplicationTarget> (SolutionApplicationTarget)>
974+
rewriteTarget) {
975+
BuilderClosureRewriter rewriter(solution, dc, applied, rewriteTarget);
960976
auto captured = rewriter.takeCapturedStmt(body);
961977
return cast<BraceStmt>(
962978
rewriter.visitBraceStmt(

lib/Sema/CSApply.cpp

Lines changed: 102 additions & 84 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) {}
@@ -7063,14 +7063,14 @@ namespace {
70637063
llvm::SaveAndRestore<DeclContext *> savedDC(Rewriter.dc, closure);
70647064
auto newBody = applyFunctionBuilderTransform(
70657065
Rewriter.solution, *transform, closure->getBody(), closure,
7066-
[&](Expr *expr) {
7067-
Expr *result = expr->walk(*this);
7068-
if (result)
7069-
Rewriter.solution.setExprTypes(result);
7070-
return result;
7071-
},
7072-
[&](Expr *expr, Type toType, ConstraintLocator *locator) {
7073-
return Rewriter.coerceToType(expr, toType, locator);
7066+
[&](SolutionApplicationTarget target) {
7067+
auto resultTarget = rewriteTarget(target);
7068+
if (resultTarget) {
7069+
if (auto expr = resultTarget->getAsExpr())
7070+
Rewriter.solution.setExprTypes(expr);
7071+
}
7072+
7073+
return resultTarget;
70747074
});
70757075
closure->setBody(newBody, /*isSingleExpression=*/false);
70767076
closure->setAppliedFunctionBuilder();
@@ -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(),
7366-
[&](Expr *expr) {
7367-
Expr *result = expr->walk(walker);
7368-
if (result)
7369-
solution.setExprTypes(result);
7370-
return result;
7371-
},
7372-
[&](Expr *expr, Type toType, ConstraintLocator *locator) {
7373-
return rewriter.coerceToType(expr, toType, locator);
7343+
[&](SolutionApplicationTarget target) {
7344+
auto resultTarget = rewriteTarget(target);
7345+
if (resultTarget) {
7346+
if (auto expr = resultTarget->getAsExpr())
7347+
Rewriter.solution.setExprTypes(expr);
7348+
}
7349+
7350+
return resultTarget;
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);

0 commit comments

Comments
 (0)