@@ -849,11 +849,29 @@ StepResult ConjunctionStep::resume(bool prevFailed) {
849
849
850
850
// There could be a local ambiguity related to
851
851
// the current element, let's try to resolve it.
852
- if (Solutions.size () > 1 ) {
852
+ if (Solutions.size () > 1 )
853
853
filterSolutions (Solutions, /* minimize=*/ true );
854
854
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 ();
857
875
}
858
876
859
877
// Since there is only one solution, let's
@@ -885,34 +903,44 @@ StepResult ConjunctionStep::resume(bool prevFailed) {
885
903
log << " (applying conjunction result to outer context\n " ;
886
904
}
887
905
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.
893
906
assert (
894
907
Snapshot &&
895
908
" Isolated conjunction requires a snapshot of the constraint system" );
896
- Snapshot->setupOuterContext (Solutions.pop_back_val ());
897
909
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 );
911
935
}
912
936
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 ();
916
944
917
945
// Now that all of the information from the conjunction has
918
946
// been applied, let's attempt to solve the outer scope.
@@ -923,3 +951,24 @@ StepResult ConjunctionStep::resume(bool prevFailed) {
923
951
// Attempt next conjunction choice.
924
952
return take (prevFailed);
925
953
}
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