Skip to content

Commit 86e11c5

Browse files
authored
Merge pull request #19353 from xedin/add-binding-step
[CSStep] Add `BindingStep` to unify some logic in `TypeVar`, `Disjunction` steps
2 parents 31df1ed + 82d07ad commit 86e11c5

File tree

4 files changed

+171
-238
lines changed

4 files changed

+171
-238
lines changed

lib/Sema/CSSolver.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1406,17 +1406,17 @@ bool DisjunctionChoice::attempt(ConstraintSystem &cs) const {
14061406
return !cs.failedConstraint && !cs.simplify();
14071407
}
14081408

1409-
bool DisjunctionChoice::isGenericOp(Constraint *choice) {
1410-
auto *decl = getOperatorDecl(choice);
1409+
bool DisjunctionChoice::isGenericOperator() const {
1410+
auto *decl = getOperatorDecl(Choice);
14111411
if (!decl)
14121412
return false;
14131413

14141414
auto interfaceType = decl->getInterfaceType();
14151415
return interfaceType->is<GenericFunctionType>();
14161416
}
14171417

1418-
bool DisjunctionChoice::isSymmetricOp(Constraint *choice) {
1419-
auto *decl = getOperatorDecl(choice);
1418+
bool DisjunctionChoice::isSymmetricOperator() const {
1419+
auto *decl = getOperatorDecl(Choice);
14201420
if (!decl)
14211421
return false;
14221422

lib/Sema/CSStep.cpp

Lines changed: 28 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -350,110 +350,52 @@ void TypeVariableStep::setup() {
350350
}
351351
}
352352

353-
StepResult TypeVariableStep::take(bool prevFailed) {
354-
while (auto binding = Producer()) {
355-
// Try each of the bindings in turn.
356-
++CS.solverState->NumTypeVariableBindings;
357-
358-
if (AnySolved) {
359-
// If this is a defaultable binding and we have found solutions,
360-
// don't explore the default binding.
361-
if (binding->isDefaultable())
362-
continue;
363-
364-
// If we were able to solve this without considering
365-
// default literals, don't bother looking at default literals.
366-
if (binding->hasDefaultedProtocol() && !SawFirstLiteralConstraint)
367-
break;
368-
}
353+
bool TypeVariableStep::attempt(const TypeVariableBinding &choice) {
354+
++CS.solverState->NumTypeVariableBindings;
369355

370-
if (isDebugMode()) {
371-
auto &log = getDebugLogger();
372-
log << "(trying ";
373-
binding->print(log, &CS.getASTContext().SourceMgr);
374-
log << '\n';
375-
}
356+
if (isDebugMode()) {
357+
auto &log = getDebugLogger();
358+
log << "(trying ";
359+
choice.print(log, &CS.getASTContext().SourceMgr);
360+
log << '\n';
361+
}
376362

377-
if (binding->hasDefaultedProtocol())
378-
SawFirstLiteralConstraint = true;
379-
380-
{
381-
// Try to solve the system with typeVar := type
382-
auto scope = llvm::make_unique<Scope>(CS);
383-
if (binding->attempt(CS)) {
384-
ActiveChoice = std::move(scope);
385-
// Looks like binding attempt has been successful,
386-
// let's try to see if it leads to any solutions.
387-
return suspend(SplitterStep::create(CS, Solutions));
388-
}
389-
}
363+
if (choice.hasDefaultedProtocol())
364+
SawFirstLiteralConstraint = true;
390365

366+
// Try to solve the system with typeVar := type
367+
if (!choice.attempt(CS)) {
391368
if (isDebugMode())
392369
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;
370+
return false;
398371
}
399372

400-
// No more bindings to try, or producer has been short-circuited.
401-
return done(/*isSuccess=*/AnySolved);
373+
return true;
402374
}
403375

404376
StepResult TypeVariableStep::resume(bool prevFailed) {
405377
assert(ActiveChoice);
406378

407-
// Rewind back all of the changes made to constraint system.
408-
ActiveChoice.reset();
409-
410379
// If there was no failure in the sub-path it means
411380
// that active binding has a solution.
412381
AnySolved |= !prevFailed;
413382

414383
if (isDebugMode())
415384
getDebugLogger() << ")\n";
416385

386+
const auto choice = ActiveChoice->second;
387+
// Rewind back all of the changes made to constraint system.
388+
ActiveChoice.reset();
389+
417390
// Let's check if we should stop right before
418391
// attempting any new bindings.
419-
if (shouldStop())
392+
if (shouldStopAfter(choice))
420393
return done(/*isSuccess=*/AnySolved);
421394

422395
// Attempt next type variable binding.
423396
return take(prevFailed);
424397
}
425398

426-
StepResult DisjunctionStep::take(bool prevFailed) {
427-
while (auto binding = Producer()) {
428-
auto &currentChoice = *binding;
429-
430-
if (shouldSkipChoice(currentChoice))
431-
continue;
432-
433-
if (shouldShortCircuitAt(currentChoice))
434-
break;
435-
436-
if (isDebugMode()) {
437-
auto &log = getDebugLogger();
438-
log << "(assuming ";
439-
currentChoice.print(log, &CS.getASTContext().SourceMgr);
440-
log << '\n';
441-
}
442-
443-
/// Attempt given disjunction choice, which is going to simplify
444-
/// constraint system by binding some of the type variables. Since
445-
/// the system has been simplified and is splittable, we simplify
446-
/// have to return "split" step which is going to take care of the rest.
447-
if (attemptChoice(currentChoice))
448-
return suspend(SplitterStep::create(CS, Solutions));
449-
450-
if (isDebugMode())
451-
getDebugLogger() << ")\n";
452-
}
453-
454-
return done(/*isSuccess=*/bool(LastSolvedChoice));
455-
}
456-
457399
StepResult DisjunctionStep::resume(bool prevFailed) {
458400
// If disjunction step is re-taken and there should be
459401
// active choice, let's see if it has be solved or not.
@@ -472,6 +414,7 @@ StepResult DisjunctionStep::resume(bool prevFailed) {
472414
BestNonGenericScore = score;
473415
}
474416

417+
AnySolved = true;
475418
// Remember the last successfully solved choice,
476419
// it would be useful when disjunction is exhausted.
477420
LastSolvedChoice = {choice, *score};
@@ -487,7 +430,7 @@ StepResult DisjunctionStep::resume(bool prevFailed) {
487430
return take(prevFailed);
488431
}
489432

490-
bool DisjunctionStep::shouldSkipChoice(const TypeBinding &choice) const {
433+
bool DisjunctionStep::shouldSkip(const DisjunctionChoice &choice) const {
491434
auto &ctx = CS.getASTContext();
492435

493436
if (choice.isDisabled()) {
@@ -531,8 +474,7 @@ bool DisjunctionStep::shouldSkipChoice(const TypeBinding &choice) const {
531474
return false;
532475
}
533476

534-
bool DisjunctionStep::shouldShortCircuitAt(
535-
const DisjunctionChoice &choice) const {
477+
bool DisjunctionStep::shouldStopAt(const DisjunctionChoice &choice) const {
536478
if (!LastSolvedChoice)
537479
return false;
538480

@@ -596,13 +538,12 @@ bool DisjunctionStep::shortCircuitDisjunctionAt(
596538
return false;
597539
}
598540

599-
bool DisjunctionStep::attemptChoice(const DisjunctionChoice &choice) {
600-
auto scope = llvm::make_unique<Scope>(CS);
541+
bool DisjunctionStep::attempt(const DisjunctionChoice &choice) {
601542
++CS.solverState->NumDisjunctionTerms;
602543

603544
// If the disjunction requested us to, remember which choice we
604545
// took for it.
605-
if (auto *disjunctionLocator = Producer.getLocator()) {
546+
if (auto *disjunctionLocator = getLocator()) {
606547
auto index = choice.getIndex();
607548
recordDisjunctionChoice(disjunctionLocator, index);
608549

@@ -619,11 +560,11 @@ bool DisjunctionStep::attemptChoice(const DisjunctionChoice &choice) {
619560
}
620561
}
621562

622-
if (!choice.attempt(CS))
563+
if (!choice.attempt(CS)) {
564+
if (isDebugMode())
565+
getDebugLogger() << ")\n";
623566
return false;
567+
}
624568

625-
// Establish the "active" choice which maintains new scope in the
626-
// constraint system, be be able to rollback all of the changes later.
627-
ActiveChoice.emplace(std::move(scope), choice);
628569
return true;
629570
}

0 commit comments

Comments
 (0)