@@ -513,11 +513,32 @@ TypeChecker::getTypeOfCompletionOperator(DeclContext *DC, Expr *LHS,
513513 }
514514}
515515
516- // / Remove any solutions from the provided vector that both require fixes and
517- // / have a score worse than the best.
518- static void filterSolutions (SolutionApplicationTarget &target,
519- SmallVectorImpl<Solution> &solutions,
520- CodeCompletionExpr *completionExpr) {
516+ static bool hasTypeForCompletion (Solution &solution,
517+ CompletionContextFinder &contextAnalyzer) {
518+ if (contextAnalyzer.hasCompletionExpr ()) {
519+ return solution.hasType (contextAnalyzer.getCompletionExpr ());
520+ } else {
521+ assert (contextAnalyzer.hasCompletionKeyPathComponent ());
522+ return solution.hasType (
523+ contextAnalyzer.getKeyPathContainingCompletionComponent (),
524+ contextAnalyzer.getKeyPathCompletionComponentIndex ());
525+ }
526+ }
527+
528+ void TypeChecker::filterSolutionsForCodeCompletion (
529+ SmallVectorImpl<Solution> &solutions,
530+ CompletionContextFinder &contextAnalyzer) {
531+ // Ignore solutions that didn't end up involving the completion (e.g. due to
532+ // a fix to skip over/ignore it).
533+ llvm::erase_if (solutions, [&](Solution &S) {
534+ if (hasTypeForCompletion (S, contextAnalyzer))
535+ return false ;
536+ // FIXME: Technically this should never happen, but it currently does in
537+ // result builder contexts. Re-evaluate if we can assert here when we have
538+ // multi-statement closure checking for result builders.
539+ return true ;
540+ });
541+
521542 if (solutions.size () <= 1 )
522543 return ;
523544
@@ -608,15 +629,6 @@ bool TypeChecker::typeCheckForCodeCompletion(
608629 if (!cs.solveForCodeCompletion (target, solutions))
609630 return CompletionResult::Fallback;
610631
611- // FIXME: instead of filtering, expose the score and viability to clients.
612- // Remove any solutions that both require fixes and have a score that is
613- // worse than the best.
614- CodeCompletionExpr *completionExpr = nullptr ;
615- if (contextAnalyzer.hasCompletionExpr ()) {
616- completionExpr = contextAnalyzer.getCompletionExpr ();
617- }
618- filterSolutions (target, solutions, completionExpr);
619-
620632 // Similarly, if the type-check didn't produce any solutions, fall back
621633 // to type-checking a sub-expression in isolation.
622634 if (solutions.empty ())
@@ -626,19 +638,7 @@ bool TypeChecker::typeCheckForCodeCompletion(
626638 // closure body it could either be type-checked together with the context
627639 // or not, it's impossible to say without checking.
628640 if (contextAnalyzer.locatedInMultiStmtClosure ()) {
629- auto &solution = solutions.front ();
630-
631- bool HasTypeForCompletionNode = false ;
632- if (completionExpr) {
633- HasTypeForCompletionNode = solution.hasType (completionExpr);
634- } else {
635- assert (contextAnalyzer.hasCompletionKeyPathComponent ());
636- HasTypeForCompletionNode = solution.hasType (
637- contextAnalyzer.getKeyPathContainingCompletionComponent (),
638- contextAnalyzer.getKeyPathCompletionComponentIndex ());
639- }
640-
641- if (!HasTypeForCompletionNode) {
641+ if (!hasTypeForCompletion (solutions.front (), contextAnalyzer)) {
642642 // At this point we know the code completion node wasn't checked with
643643 // the closure's surrounding context, so can defer to regular
644644 // type-checking for the current call to typeCheckExpression. If that
@@ -651,6 +651,11 @@ bool TypeChecker::typeCheckForCodeCompletion(
651651 }
652652 }
653653
654+ // FIXME: instead of filtering, expose the score and viability to clients.
655+ // Remove solutions that skipped over/ignored the code completion point
656+ // or that require fixes and have a score that is worse than the best.
657+ filterSolutionsForCodeCompletion (solutions, contextAnalyzer);
658+
654659 llvm::for_each (solutions, callback);
655660 return CompletionResult::Ok;
656661 };
0 commit comments