@@ -126,6 +126,7 @@ void SplitterStep::computeFollowupSteps(
126126 // Take the orphaned constraints, because they'll go into a component now.
127127 OrphanedConstraints = CG.takeOrphanedConstraints ();
128128
129+ IncludeInMergedResults.resize (numComponents, true );
129130 Components.resize (numComponents);
130131 PartialSolutions = std::unique_ptr<SmallVector<Solution, 4 >[]>(
131132 new SmallVector<Solution, 4 >[numComponents]);
@@ -134,9 +135,26 @@ void SplitterStep::computeFollowupSteps(
134135 for (unsigned i : indices (components)) {
135136 unsigned solutionIndex = components[i].solutionIndex ;
136137
137- steps.push_back (std::make_unique<ComponentStep>(
138- CS, solutionIndex, &Components[i], std::move (components[i]),
139- PartialSolutions[solutionIndex]));
138+ // If there are no dependencies, build a normal component step.
139+ if (components[i].getDependencies ().empty ()) {
140+ steps.push_back (std::make_unique<ComponentStep>(
141+ CS, solutionIndex, &Components[i], std::move (components[i]),
142+ PartialSolutions[solutionIndex]));
143+ continue ;
144+ }
145+
146+ // Note that the partial results from any dependencies of this component
147+ // need not be included in the final merged results, because they'll
148+ // already be part of the partial results for this component.
149+ for (auto dependsOn : components[i].getDependencies ()) {
150+ IncludeInMergedResults[dependsOn] = false ;
151+ }
152+
153+ // Otherwise, build a dependent component "splitter" step, which
154+ // handles all combinations of incoming partial solutions.
155+ steps.push_back (std::make_unique<DependentComponentSplitterStep>(
156+ CS, &Components[i], solutionIndex, std::move (components[i]),
157+ llvm::MutableArrayRef (PartialSolutions.get (), numComponents)));
140158 }
141159
142160 assert (CS.InactiveConstraints .empty () && " Missed a constraint" );
@@ -205,7 +223,8 @@ bool SplitterStep::mergePartialSolutions() const {
205223 SmallVector<unsigned , 2 > countsVec;
206224 countsVec.reserve (numComponents);
207225 for (unsigned idx : range (numComponents)) {
208- countsVec.push_back (PartialSolutions[idx].size ());
226+ countsVec.push_back (
227+ IncludeInMergedResults[idx] ? PartialSolutions[idx].size () : 1 );
209228 }
210229
211230 // Produce all combinations of partial solutions.
@@ -218,6 +237,9 @@ bool SplitterStep::mergePartialSolutions() const {
218237 // solutions.
219238 ConstraintSystem::SolverScope scope (CS);
220239 for (unsigned i : range (numComponents)) {
240+ if (!IncludeInMergedResults[i])
241+ continue ;
242+
221243 CS.replaySolution (PartialSolutions[i][indices[i]]);
222244 }
223245
@@ -249,15 +271,77 @@ bool SplitterStep::mergePartialSolutions() const {
249271 return anySolutions;
250272}
251273
274+ StepResult DependentComponentSplitterStep::take (bool prevFailed) {
275+ // "split" is considered a failure if previous step failed,
276+ // or there is a failure recorded by constraint system, or
277+ // system can't be simplified.
278+ if (prevFailed || CS.getFailedConstraint () || CS.simplify ())
279+ return done (/* isSuccess=*/ false );
280+
281+ // Figure out the sets of partial solutions that this component depends on.
282+ SmallVector<const SmallVector<Solution, 4 > *, 2 > dependsOnSets;
283+ for (auto index : Component.getDependencies ()) {
284+ dependsOnSets.push_back (&AllPartialSolutions[index]);
285+ }
286+
287+ // Produce all combinations of partial solutions for the inputs.
288+ SmallVector<std::unique_ptr<SolverStep>, 4 > followup;
289+ SmallVector<unsigned , 2 > indices (Component.getDependencies ().size (), 0 );
290+ auto dependsOnSetsRef = llvm::ArrayRef (dependsOnSets);
291+ do {
292+ // Form the set of input partial solutions.
293+ SmallVector<const Solution *, 2 > dependsOnSolutions;
294+ for (auto index : swift::indices (indices)) {
295+ dependsOnSolutions.push_back (&(*dependsOnSets[index])[indices[index]]);
296+ }
297+ ContextualSolutions.push_back (std::make_unique<SmallVector<Solution, 2 >>());
298+
299+ followup.push_back (std::make_unique<ComponentStep>(
300+ CS, Index, Constraints, Component, std::move (dependsOnSolutions),
301+ *ContextualSolutions.back ()));
302+ } while (nextCombination (dependsOnSetsRef, indices));
303+
304+ // / Wait until all of the component steps are done.
305+ return suspend (followup);
306+ }
307+
308+ StepResult DependentComponentSplitterStep::resume (bool prevFailed) {
309+ for (auto &ComponentStepSolutions : ContextualSolutions) {
310+ Solutions.append (std::make_move_iterator (ComponentStepSolutions->begin ()),
311+ std::make_move_iterator (ComponentStepSolutions->end ()));
312+ }
313+ return done (/* isSuccess=*/ !Solutions.empty ());
314+ }
315+
316+ void DependentComponentSplitterStep::print (llvm::raw_ostream &Out) {
317+ Out << " DependentComponentSplitterStep for dependencies on [" ;
318+ interleave (
319+ Component.getDependencies (), [&](unsigned index) { Out << index; },
320+ [&] { Out << " , " ; });
321+ Out << " ]\n " ;
322+ }
323+
252324StepResult ComponentStep::take (bool prevFailed) {
253325 // One of the previous components created by "split"
254326 // failed, it means that we can't solve this component.
255- if (prevFailed || CS.isTooComplex (Solutions) || CS.worseThanBestSolution ())
327+ if ((prevFailed && DependsOnPartialSolutions.empty ()) ||
328+ CS.isTooComplex (Solutions) || CS.worseThanBestSolution ())
256329 return done (/* isSuccess=*/ false );
257330
258331 // Setup active scope, only if previous component didn't fail.
259332 setupScope ();
260333
334+ // If there are any dependent partial solutions to compose, do so now.
335+ if (!DependsOnPartialSolutions.empty ()) {
336+ for (auto partial : DependsOnPartialSolutions) {
337+ CS.replaySolution (*partial);
338+ }
339+
340+ // Simplify again.
341+ if (CS.failedConstraint || CS.simplify ())
342+ return done (/* isSuccess=*/ false );
343+ }
344+
261345 // / Try to figure out what this step is going to be,
262346 // / after the scope has been established.
263347 SmallString<64 > potentialBindings;
0 commit comments