Skip to content

Commit 04f48db

Browse files
authored
Merge pull request #76932 from slavapestov/cstrail-part-6
Sema: Small SolverTrail cleanups
2 parents 131ab89 + cdc2145 commit 04f48db

File tree

6 files changed

+83
-54
lines changed

6 files changed

+83
-54
lines changed

include/swift/Sema/ConstraintSystem.h

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2143,8 +2143,6 @@ class ConstraintSystem {
21432143
friend struct ClosureIsolatedByPreconcurrency;
21442144
friend class SolverTrail;
21452145

2146-
class SolverScope;
2147-
21482146
/// Expressions that are known to be unevaluated.
21492147
/// Note: this is only used to support ObjCSelectorExpr at the moment.
21502148
llvm::SmallPtrSet<Expr *, 2> UnevaluatedRootExprs;
@@ -2555,23 +2553,21 @@ class ConstraintSystem {
25552553
}
25562554

25572555
/// Update statistics when a scope begins.
2558-
///
2559-
/// \param scope The scope to associate with current solver state.
2560-
void beginScope(SolverScope *scope) {
2556+
unsigned beginScope() {
25612557
++depth;
25622558
maxDepth = std::max(maxDepth, depth);
2563-
scope->scopeNumber = NumStatesExplored++;
25642559

25652560
CS.incrementScopeCounter();
2561+
2562+
return NumStatesExplored++;
25662563
}
25672564

25682565
/// Update statistics when a scope ends.
2569-
///
2570-
/// \param scope The solver scope to rollback.
2571-
void endScope(SolverScope *scope) {
2566+
void endScope(unsigned scopeNumber) {
2567+
ASSERT(depth > 0);
25722568
--depth;
25732569

2574-
unsigned countScopesExplored = NumStatesExplored - scope->scopeNumber;
2570+
unsigned countScopesExplored = NumStatesExplored - scopeNumber;
25752571
if (countScopesExplored == 1)
25762572
CS.incrementLeafScopes();
25772573
}
@@ -2775,7 +2771,7 @@ class ConstraintSystem {
27752771
/// this object is destroyed.
27762772
///
27772773
///
2778-
class SolverScope {
2774+
struct SolverScope {
27792775
ConstraintSystem &cs;
27802776

27812777
/// The length of \c TypeVariables.
@@ -2785,15 +2781,19 @@ class ConstraintSystem {
27852781
unsigned numTrailChanges;
27862782

27872783
/// The scope number of this scope. Set when the scope is registered.
2788-
unsigned scopeNumber = 0;
2784+
unsigned scopeNumber : 31;
2785+
2786+
/// A moved-from scope skips doing anything in the destructor.
2787+
unsigned moved : 1;
2788+
2789+
explicit SolverScope(ConstraintSystem &cs);
27892790

27902791
SolverScope(const SolverScope &) = delete;
2791-
SolverScope &operator=(const SolverScope &) = delete;
2792+
SolverScope(SolverScope &&other);
27922793

2793-
friend class ConstraintSystem;
2794+
SolverScope &operator=(const SolverScope &) = delete;
2795+
SolverScope &operator=(SolverScope &&) = delete;
27942796

2795-
public:
2796-
explicit SolverScope(ConstraintSystem &cs);
27972797
~SolverScope();
27982798
};
27992799

@@ -5465,6 +5465,15 @@ class ConstraintSystem {
54655465
/// Primitive form of the above. Records a change in the trail.
54665466
void increaseScore(ScoreKind kind, unsigned value);
54675467

5468+
/// Apply the score from a partial solution. Records the change in the
5469+
/// trail.
5470+
void replayScore(const Score &score);
5471+
5472+
/// Temporarily zero out the score, and record this in the trail so that
5473+
/// we restore the score when the scope ends. Used when solving a
5474+
/// ConjunctionStep.
5475+
void clearScore();
5476+
54685477
/// Determine whether this solution is guaranteed to be worse than the best
54695478
/// solution found so far.
54705479
bool worseThanBestSolution() const;

lib/Sema/CSRanking.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,27 @@ void ConstraintSystem::increaseScore(ScoreKind kind,
146146
increaseScore(kind, value);
147147
}
148148

149+
void ConstraintSystem::replayScore(const Score &score) {
150+
if (solverState) {
151+
for (unsigned i = 0; i < NumScoreKinds; ++i) {
152+
if (unsigned value = score.Data[i])
153+
recordChange(
154+
SolverTrail::Change::IncreasedScore(ScoreKind(i), value));
155+
}
156+
}
157+
CurrentScore += score;
158+
}
159+
160+
void ConstraintSystem::clearScore() {
161+
for (unsigned i = 0; i < NumScoreKinds; ++i) {
162+
if (unsigned value = CurrentScore.Data[i]) {
163+
recordChange(
164+
SolverTrail::Change::DecreasedScore(ScoreKind(i), value));
165+
}
166+
}
167+
CurrentScore = Score();
168+
}
169+
149170
bool ConstraintSystem::worseThanBestSolution() const {
150171
if (getASTContext().TypeCheckerOpts.DisableConstraintSolverPerformanceHacks)
151172
return false;

lib/Sema/CSSolver.cpp

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -271,15 +271,8 @@ Solution ConstraintSystem::finalize() {
271271

272272
void ConstraintSystem::replaySolution(const Solution &solution,
273273
bool shouldIncreaseScore) {
274-
if (shouldIncreaseScore) {
275-
// Update the score. We do this instead of operator+= because we
276-
// want to record the increments in the trail.
277-
auto solutionScore = solution.getFixedScore();
278-
for (unsigned i = 0; i < NumScoreKinds; ++i) {
279-
if (unsigned value = solutionScore.Data[i])
280-
increaseScore(ScoreKind(i), value);
281-
}
282-
}
274+
if (shouldIncreaseScore)
275+
replayScore(solution.getFixedScore());
283276

284277
// Assign fixed types to the type variables solved by this solution.
285278
for (auto binding : solution.typeBindings) {
@@ -702,21 +695,32 @@ ConstraintSystem::SolverState::~SolverState() {
702695
}
703696

704697
ConstraintSystem::SolverScope::SolverScope(ConstraintSystem &cs)
705-
: cs(cs) {
706-
numTrailChanges = cs.solverState->Trail.size();
707-
708-
numTypeVariables = cs.TypeVariables.size();
698+
: cs(cs),
699+
numTypeVariables(cs.TypeVariables.size()),
700+
numTrailChanges(cs.solverState->Trail.size()),
701+
scopeNumber(cs.solverState->beginScope()),
702+
moved(0) {
703+
ASSERT(!cs.failedConstraint && "Unexpected failed constraint!");
704+
}
709705

710-
cs.solverState->beginScope(this);
711-
assert(!cs.failedConstraint && "Unexpected failed constraint!");
706+
ConstraintSystem::SolverScope::SolverScope(SolverScope &&other)
707+
: cs(other.cs),
708+
numTypeVariables(other.numTypeVariables),
709+
numTrailChanges(other.numTrailChanges),
710+
scopeNumber(other.scopeNumber),
711+
moved(0) {
712+
other.moved = 1;
712713
}
713714

714715
ConstraintSystem::SolverScope::~SolverScope() {
716+
if (moved)
717+
return;
718+
715719
// Don't attempt to rollback from an incorrect state.
716720
if (cs.inInvalidState())
717721
return;
718722

719-
// Erase the end of various lists.
723+
// Roll back introduced type variables.
720724
truncate(cs.TypeVariables, numTypeVariables);
721725

722726
// Move any remaining active constraints into the inactive list.
@@ -731,7 +735,8 @@ ConstraintSystem::SolverScope::~SolverScope() {
731735
// Roll back changes to the constraint system.
732736
cs.solverState->Trail.undo(numTrailChanges);
733737

734-
cs.solverState->endScope(this);
738+
// Update statistics.
739+
cs.solverState->endScope(scopeNumber);
735740

736741
// Clear out other "failed" state.
737742
cs.failedConstraint = nullptr;

lib/Sema/CSStep.cpp

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -885,13 +885,7 @@ bool ConjunctionStep::attempt(const ConjunctionElement &element) {
885885

886886
// Make sure that element is solved in isolation
887887
// by dropping all scoring information.
888-
for (unsigned i = 0; i < NumScoreKinds; ++i) {
889-
if (unsigned value = CS.CurrentScore.Data[i]) {
890-
CS.recordChange(
891-
SolverTrail::Change::DecreasedScore(ScoreKind(i), value));
892-
}
893-
}
894-
CS.CurrentScore = Score();
888+
CS.clearScore();
895889

896890
// Reset the scope counter to avoid "too complex" failures
897891
// when closure has a lot of elements in the body.
@@ -1039,7 +1033,7 @@ StepResult ConjunctionStep::resume(bool prevFailed) {
10391033
// restored right afterwards because score of the
10401034
// element does contribute to the overall score.
10411035
restoreBestScore();
1042-
restoreCurrentScore(solution.getFixedScore());
1036+
updateScoreAfterConjunction(solution.getFixedScore());
10431037

10441038
// Transform all of the unbound outer variables into
10451039
// placeholders since we are not going to solve for
@@ -1091,10 +1085,10 @@ StepResult ConjunctionStep::resume(bool prevFailed) {
10911085
}
10921086

10931087
void ConjunctionStep::restoreOuterState(const Score &solutionScore) const {
1094-
// Restore best/current score, since upcoming step is going to
1095-
// work with outer scope in relation to the conjunction.
1088+
// Restore best score and update current score, since upcoming step
1089+
// is going to work with outer scope in relation to the conjunction.
10961090
restoreBestScore();
1097-
restoreCurrentScore(solutionScore);
1091+
updateScoreAfterConjunction(solutionScore);
10981092

10991093
// Active all of the previously out-of-scope constraints
11001094
// because conjunction can propagate type information up

lib/Sema/CSStep.h

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -519,7 +519,7 @@ template <typename P> class BindingStep : public SolverStep {
519519
/// being attempted, helps to rewind state of the
520520
/// constraint system back to original before attempting
521521
/// next binding, if any.
522-
std::optional<std::pair<std::unique_ptr<Scope>, typename P::Element>>
522+
std::optional<std::pair<Scope, typename P::Element>>
523523
ActiveChoice;
524524

525525
BindingStep(ConstraintSystem &cs, P producer,
@@ -548,16 +548,14 @@ template <typename P> class BindingStep : public SolverStep {
548548
}
549549

550550
{
551-
auto &trail = CS.solverState->Trail;
552-
unsigned size = trail.size();
553-
554-
auto scope = std::make_unique<Scope>(CS);
551+
Scope scope(CS);
555552
if (attempt(*choice)) {
556553
ActiveChoice.emplace(std::move(scope), *choice);
557554

558555
if (CS.isDebugMode()) {
559-
trail.dumpActiveScopeChanges(
560-
llvm::errs(), size, CS.solverState->getCurrentIndent());
556+
CS.solverState->Trail.dumpActiveScopeChanges(
557+
llvm::errs(), ActiveChoice->first.numTrailChanges,
558+
CS.solverState->getCurrentIndent());
561559
}
562560

563561
return suspend(std::make_unique<SplitterStep>(CS, Solutions));
@@ -1029,8 +1027,10 @@ class ConjunctionStep : public BindingStep<ConjunctionElementProducer> {
10291027
}
10301028

10311029
private:
1032-
/// Restore best and current scores as they were before conjunction.
1033-
void restoreCurrentScore(const Score &solutionScore) const {
1030+
/// We need to do this to make sure that we rank solutions with
1031+
/// invalid closures appropriately and don’t produce a valid
1032+
/// solution if a multi-statement closure failed.
1033+
void updateScoreAfterConjunction(const Score &solutionScore) const {
10341034
CS.increaseScore(SK_Fix, Conjunction->getLocator(),
10351035
solutionScore.Data[SK_Fix]);
10361036
CS.increaseScore(SK_Hole, Conjunction->getLocator(),

lib/Sema/ConstraintGraph.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1282,7 +1282,7 @@ bool ConstraintGraph::contractEdges() {
12821282
continue;
12831283

12841284
// This closure is not currently in scope.
1285-
if (!CS.TypeVariables.count(paramTy))
1285+
if (!CS.isActiveTypeVariable(paramTy))
12861286
break;
12871287

12881288
// Nothing to contract here since outside parameter

0 commit comments

Comments
 (0)