Skip to content

Commit bec3d28

Browse files
committed
[CSStep] Add isDebugMode and getDebugLogger methods and refactor logging
Instead of using `TypeChecker` and related APIs directly every time, let's just abstract it all away to easily check if solver is running in debug mode and to produce indented logger.
1 parent c3a4434 commit bec3d28

File tree

3 files changed

+71
-66
lines changed

3 files changed

+71
-66
lines changed

lib/Sema/CSSolver.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1270,9 +1270,8 @@ void ConstraintSystem::solve(SmallVectorImpl<Solution> &solutions) {
12701270
// which should produce another steps to follow,
12711271
// or error, which means that current path is inconsistent.
12721272
{
1273-
auto currentState = step->getState();
1274-
assert(!(currentState == StepState::Running ||
1275-
currentState == StepState::Done) &&
1273+
assert(!(step->getState() == StepState::Running ||
1274+
step->getState() == StepState::Done) &&
12761275
"Cannot re-take already running/done step.");
12771276

12781277
auto result = advance(step, prevFailed);

lib/Sema/CSStep.cpp

Lines changed: 47 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "llvm/ADT/ArrayRef.h"
2222
#include "llvm/ADT/SmallVector.h"
2323
#include "llvm/ADT/STLExtras.h"
24+
#include "llvm/Support/raw_ostream.h"
2425

2526
using namespace llvm;
2627
using namespace swift;
@@ -112,10 +113,8 @@ void SplitterStep::computeFollowupSteps(
112113
CS, i, /*single=*/false, &Components[i], PartialSolutions[i]));
113114
}
114115

115-
if (numComponents > 1 && CS.getASTContext().LangOpts.DebugConstraintSolver) {
116-
auto &log = CS.getASTContext().TypeCheckerDebug->getStream().indent(
117-
CS.solverState->depth * 2);
118-
116+
if (numComponents > 1 && isDebugMode()) {
117+
auto &log = getDebugLogger();
119118
// Verify that the constraint graph is valid.
120119
CG.verify();
121120

@@ -212,11 +211,8 @@ bool SplitterStep::mergePartialSolutions() const {
212211
if (!CS.worseThanBestSolution()) {
213212
// Finalize this solution.
214213
auto solution = CS.finalize();
215-
if (CS.TC.getLangOpts().DebugConstraintSolver) {
216-
auto &log = CS.getASTContext().TypeCheckerDebug->getStream();
217-
log.indent(CS.solverState->depth * 2)
218-
<< "(composed solution " << CS.CurrentScore << ")\n";
219-
}
214+
if (isDebugMode())
215+
getDebugLogger() << "(composed solution " << CS.CurrentScore << ")\n";
220216

221217
// Save this solution.
222218
Solutions.push_back(std::move(solution));
@@ -252,12 +248,6 @@ StepResult ComponentStep::take(bool prevFailed) {
252248
if (prevFailed || CS.getExpressionTooComplex(Solutions))
253249
return done(/*isSuccess=*/false);
254250

255-
if (!IsSingle && CS.TC.getLangOpts().DebugConstraintSolver) {
256-
auto &log = CS.getASTContext().TypeCheckerDebug->getStream();
257-
log.indent(CS.solverState->depth * 2)
258-
<< "(solving component #" << Index << '\n';
259-
}
260-
261251
/// Try to figure out what this step is going to be,
262252
/// after the scope has been established.
263253
auto *disjunction = CS.selectDisjunction();
@@ -296,11 +286,8 @@ StepResult ComponentStep::take(bool prevFailed) {
296286
}
297287

298288
auto solution = CS.finalize();
299-
if (CS.TC.getLangOpts().DebugConstraintSolver) {
300-
auto &log = CS.getASTContext().TypeCheckerDebug->getStream();
301-
log.indent(CS.solverState->depth * 2)
302-
<< "(found solution " << getCurrentScore() << ")\n";
303-
}
289+
if (isDebugMode())
290+
getDebugLogger() << "(found solution " << getCurrentScore() << ")\n";
304291

305292
Solutions.push_back(std::move(solution));
306293
return done(/*isSuccess=*/true);
@@ -310,6 +297,12 @@ StepResult ComponentStep::resume(bool prevFailed) {
310297
// Rewind all modifications done to constraint system.
311298
ComponentScope.reset();
312299

300+
if (!IsSingle && isDebugMode()) {
301+
auto &log = getDebugLogger();
302+
log << (prevFailed ? "failed" : "finished") << " component #" << Index
303+
<< ")\n";
304+
}
305+
313306
// If we came either back to this step and previous
314307
// (either disjunction or type var) failed, it means
315308
// that component as a whole has failed.
@@ -341,11 +334,11 @@ StepResult ComponentStep::resume(bool prevFailed) {
341334
}
342335

343336
void TypeVariableStep::setup() {
344-
auto &TC = CS.TC;
345337
++CS.solverState->NumTypeVariablesBound;
346-
if (TC.getLangOpts().DebugConstraintSolver) {
347-
auto &log = TC.Context.TypeCheckerDebug->getStream();
348-
log.indent(CS.solverState->depth * 2) << "Initial bindings: ";
338+
if (isDebugMode()) {
339+
auto &log = getDebugLogger();
340+
341+
log << "Initial bindings: ";
349342
interleave(InitialBindings.begin(), InitialBindings.end(),
350343
[&](const Binding &binding) {
351344
log << TypeVar->getString()
@@ -358,7 +351,6 @@ void TypeVariableStep::setup() {
358351
}
359352

360353
StepResult TypeVariableStep::take(bool prevFailed) {
361-
auto &TC = CS.TC;
362354
while (auto binding = Producer()) {
363355
// Try each of the bindings in turn.
364356
++CS.solverState->NumTypeVariableBindings;
@@ -375,10 +367,10 @@ StepResult TypeVariableStep::take(bool prevFailed) {
375367
break;
376368
}
377369

378-
if (TC.getLangOpts().DebugConstraintSolver) {
379-
auto &log = TC.Context.TypeCheckerDebug->getStream();
380-
log.indent(CS.solverState->depth * 2) << "(trying ";
381-
binding->print(log, &TC.Context.SourceMgr);
370+
if (isDebugMode()) {
371+
auto &log = getDebugLogger();
372+
log << "(trying ";
373+
binding->print(log, &CS.getASTContext().SourceMgr);
382374
log << '\n';
383375
}
384376

@@ -394,12 +386,15 @@ StepResult TypeVariableStep::take(bool prevFailed) {
394386
// let's try to see if it leads to any solutions.
395387
return suspend(SplitterStep::create(CS, Solutions));
396388
}
397-
398-
// If this binding didn't match, let's check
399-
// if we've checked enough bindings to stop.
400-
if (shouldStop())
401-
break;
402389
}
390+
391+
if (isDebugMode())
392+
getDebugLogger() << ")\n";
393+
394+
// If this binding didn't match, let's check
395+
// if we've checked enough bindings to stop.
396+
if (shouldStop())
397+
break;
403398
}
404399

405400
// No more bindings to try, or producer has been short-circuited.
@@ -416,11 +411,8 @@ StepResult TypeVariableStep::resume(bool prevFailed) {
416411
// that active binding has a solution.
417412
AnySolved |= !prevFailed;
418413

419-
auto &TC = CS.TC;
420-
if (TC.getLangOpts().DebugConstraintSolver) {
421-
auto &log = TC.Context.TypeCheckerDebug->getStream();
422-
log.indent(CS.solverState->depth * 2) << ")\n";
423-
}
414+
if (isDebugMode())
415+
getDebugLogger() << ")\n";
424416

425417
// Let's check if we should stop right before
426418
// attempting any new bindings.
@@ -441,11 +433,10 @@ StepResult DisjunctionStep::take(bool prevFailed) {
441433
if (shouldShortCircuitAt(currentChoice))
442434
break;
443435

444-
if (CS.TC.getLangOpts().DebugConstraintSolver) {
445-
auto &ctx = CS.getASTContext();
446-
auto &log = ctx.TypeCheckerDebug->getStream();
447-
log.indent(CS.solverState->depth) << "(assuming ";
448-
currentChoice.print(log, &ctx.SourceMgr);
436+
if (isDebugMode()) {
437+
auto &log = getDebugLogger();
438+
log << "(assuming ";
439+
currentChoice.print(log, &CS.getASTContext().SourceMgr);
449440
log << '\n';
450441
}
451442

@@ -455,6 +446,9 @@ StepResult DisjunctionStep::take(bool prevFailed) {
455446
/// have to return "split" step which is going to take care of the rest.
456447
if (attemptChoice(currentChoice))
457448
return suspend(SplitterStep::create(CS, Solutions));
449+
450+
if (isDebugMode())
451+
getDebugLogger() << ")\n";
458452
}
459453

460454
return done(/*isSuccess=*/bool(LastSolvedChoice));
@@ -465,11 +459,6 @@ StepResult DisjunctionStep::resume(bool prevFailed) {
465459
// active choice, let's see if it has be solved or not.
466460
assert(ActiveChoice);
467461

468-
if (CS.TC.getLangOpts().DebugConstraintSolver) {
469-
auto &log = CS.getASTContext().TypeCheckerDebug->getStream();
470-
log.indent(CS.solverState->depth) << ")\n";
471-
}
472-
473462
// If choice (sub-path) has failed, it's okay, other
474463
// choices have to be attempted regardless, since final
475464
// decision could be made only after attempting all
@@ -491,18 +480,21 @@ StepResult DisjunctionStep::resume(bool prevFailed) {
491480
// Rewind back the constraint system information.
492481
ActiveChoice.reset();
493482

483+
if (isDebugMode())
484+
getDebugLogger() << ")\n";
485+
494486
// Attempt next disjunction choice (if any left).
495487
return take(prevFailed);
496488
}
497489

498490
bool DisjunctionStep::shouldSkipChoice(const TypeBinding &choice) const {
499-
auto &TC = CS.TC;
491+
auto &ctx = CS.getASTContext();
500492

501493
if (choice.isDisabled()) {
502-
if (TC.getLangOpts().DebugConstraintSolver) {
503-
auto &log = CS.getASTContext().TypeCheckerDebug->getStream();
504-
log.indent(CS.solverState->depth) << "(skipping ";
505-
choice.print(log, &TC.Context.SourceMgr);
494+
if (isDebugMode()) {
495+
auto &log = getDebugLogger();
496+
log << "(skipping ";
497+
choice.print(log, &ctx.SourceMgr);
506498
log << '\n';
507499
}
508500

@@ -513,7 +505,7 @@ bool DisjunctionStep::shouldSkipChoice(const TypeBinding &choice) const {
513505
if (!CS.shouldAttemptFixes() && choice.isUnavailable())
514506
return true;
515507

516-
if (TC.getLangOpts().DisableConstraintSolverPerformanceHacks)
508+
if (ctx.LangOpts.DisableConstraintSolverPerformanceHacks)
517509
return false;
518510

519511
// Don't attempt to solve for generic operators if we already have

lib/Sema/CSStep.h

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "llvm/ADT/ArrayRef.h"
2525
#include "llvm/ADT/Optional.h"
2626
#include "llvm/ADT/SmallVector.h"
27+
#include "llvm/Support/raw_ostream.h"
2728
#include <memory>
2829

2930
using namespace llvm;
@@ -214,6 +215,15 @@ class SolverStep {
214215
if (!CS.retainAllSolutions())
215216
CS.filterSolutions(solutions, CS.solverState->ExprWeights, minimize);
216217
}
218+
219+
/// Check whether constraint solver is running in "debug" mode,
220+
/// which should output diagnostic information.
221+
bool isDebugMode() const { return CS.TC.getLangOpts().DebugConstraintSolver; }
222+
223+
llvm::raw_ostream &getDebugLogger(bool indent = true) const {
224+
auto &log = CS.getASTContext().TypeCheckerDebug->getStream();
225+
return indent ? log.indent(CS.solverState->depth * 2) : log;
226+
}
217227
};
218228

219229
/// `SplitterStep` is responsible for running connected components
@@ -354,14 +364,18 @@ class ComponentStep final : public SolverStep {
354364
}
355365

356366
void setup() override {
357-
// If this is a single component, there is
358-
// no need to preliminary modify constraint system.
359-
if (!IsSingle) {
360-
ComponentScope = llvm::make_unique<Scope>(*this);
361-
// If this component has oprhaned constraint attached,
362-
// let's return it ot the graph.
363-
CS.CG.setOrphanedConstraint(OrphanedConstraint);
364-
}
367+
// If this is a single component, there is no need
368+
// to preliminary modify constraint system or log anything.
369+
if (IsSingle)
370+
return;
371+
372+
if (isDebugMode())
373+
getDebugLogger() << "(solving component #" << Index << '\n';
374+
375+
ComponentScope = llvm::make_unique<Scope>(*this);
376+
// If this component has oprhaned constraint attached,
377+
// let's return it ot the graph.
378+
CS.CG.setOrphanedConstraint(OrphanedConstraint);
365379
}
366380

367381
StepResult take(bool prevFailed) override;

0 commit comments

Comments
 (0)