@@ -849,11 +849,29 @@ StepResult ConjunctionStep::resume(bool prevFailed) {
849849
850850 // There could be a local ambiguity related to
851851 // the current element, let's try to resolve it.
852- if (Solutions.size () > 1 ) {
852+ if (Solutions.size () > 1 )
853853 filterSolutions (Solutions, /* minimize=*/ true );
854854
855- if (Solutions.size () != 1 )
856- return failConjunction ();
855+ // In diagnostic mode we need to stop a conjunction
856+ // but consider it successful if there are:
857+ //
858+ // - More than one solution for this element. Ambiguity
859+ // needs to get propagated back to the outer context
860+ // to be diagnosed.
861+ // - A single solution that requires one or more fixes,
862+ // continuing would result in more errors associated
863+ // with the failed element.
864+ if (CS.shouldAttemptFixes ()) {
865+ if (Solutions.size () > 1 )
866+ Producer.markExhausted ();
867+
868+ if (Solutions.size () == 1 ) {
869+ auto score = Solutions.front ().getFixedScore ();
870+ if (score.Data [SK_Fix] > 0 )
871+ Producer.markExhausted ();
872+ }
873+ } else if (Solutions.size () != 1 ) {
874+ return failConjunction ();
857875 }
858876
859877 // Since there is only one solution, let's
@@ -885,34 +903,44 @@ StepResult ConjunctionStep::resume(bool prevFailed) {
885903 log << " (applying conjunction result to outer context\n " ;
886904 }
887905
888- // Restore constraint system state before conjunction.
889- //
890- // Note that this doesn't include conjunction constraint
891- // itself because we don't want to re-solve it at this
892- // point.
893906 assert (
894907 Snapshot &&
895908 " Isolated conjunction requires a snapshot of the constraint system" );
896- Snapshot->setupOuterContext (Solutions.pop_back_val ());
897909
898- // Restore best score, since upcoming step is going to
899- // work with outer scope in relation to the conjunction.
900- CS.solverState ->BestScore = BestScore;
901-
902- // Active all of the previously out-of-scope constraints
903- // because conjunction can propagate type information up
904- // by allowing its elements to reference type variables
905- // from outer scope (e.g. variable declarations and or captures).
906- {
907- CS.ActiveConstraints .splice (CS.ActiveConstraints .end (),
908- CS.InactiveConstraints );
909- for (auto &constraint : CS.ActiveConstraints )
910- constraint.setActive (true );
910+ // In diagnostic mode it's valid for an element to have
911+ // multiple solutions. Ambiguity just needs to be merged
912+ // into the outer context to be property diagnosed.
913+ if (Solutions.size () > 1 ) {
914+ assert (CS.shouldAttemptFixes ());
915+
916+ // Restore all outer type variables, constraints
917+ // and scoring information.
918+ Snapshot.reset ();
919+ restoreOuterState ();
920+
921+ // Apply all of the information deduced from the
922+ // conjunction (up to the point of ambiguity)
923+ // back to the outer context and form a joined solution.
924+ for (auto &solution : Solutions) {
925+ ConstraintSystem::SolverScope scope (CS);
926+
927+ CS.applySolution (solution);
928+ // Note that `worseThanBestSolution` isn't checked
929+ // here because `Solutions` were pre-filtered, and
930+ // outer score is the same for all of them.
931+ OuterSolutions.push_back (CS.finalize ());
932+ }
933+
934+ return done (/* isSuccess=*/ true );
911935 }
912936
913- // Restore score to the one before conjunction. This has
914- // be done after solution, reached for the body, is applied.
915- CS.CurrentScore = CurrentScore;
937+ // Restore outer type variables and prepare to solve
938+ // constraints associated with outer context together
939+ // with information deduced from the conjunction.
940+ Snapshot->setupOuterContext (Solutions.pop_back_val ());
941+
942+ // Pretend that conjunction never happend.
943+ restoreOuterState ();
916944
917945 // Now that all of the information from the conjunction has
918946 // been applied, let's attempt to solve the outer scope.
@@ -923,3 +951,24 @@ StepResult ConjunctionStep::resume(bool prevFailed) {
923951 // Attempt next conjunction choice.
924952 return take (prevFailed);
925953}
954+
955+ void ConjunctionStep::restoreOuterState () const {
956+ // Restore best score, since upcoming step is going to
957+ // work with outer scope in relation to the conjunction.
958+ CS.solverState ->BestScore = BestScore;
959+
960+ // Active all of the previously out-of-scope constraints
961+ // because conjunction can propagate type information up
962+ // by allowing its elements to reference type variables
963+ // from outer scope (e.g. variable declarations and or captures).
964+ {
965+ CS.ActiveConstraints .splice (CS.ActiveConstraints .end (),
966+ CS.InactiveConstraints );
967+ for (auto &constraint : CS.ActiveConstraints )
968+ constraint.setActive (true );
969+ }
970+
971+ // Restore score to the one before conjunction. This has
972+ // be done after solution, reached for the body, is applied.
973+ CS.CurrentScore = CurrentScore;
974+ }
0 commit comments