@@ -513,11 +513,32 @@ TypeChecker::getTypeOfCompletionOperator(DeclContext *DC, Expr *LHS,
513
513
}
514
514
}
515
515
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
+
521
542
if (solutions.size () <= 1 )
522
543
return ;
523
544
@@ -608,15 +629,6 @@ bool TypeChecker::typeCheckForCodeCompletion(
608
629
if (!cs.solveForCodeCompletion (target, solutions))
609
630
return CompletionResult::Fallback;
610
631
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
-
620
632
// Similarly, if the type-check didn't produce any solutions, fall back
621
633
// to type-checking a sub-expression in isolation.
622
634
if (solutions.empty ())
@@ -626,19 +638,7 @@ bool TypeChecker::typeCheckForCodeCompletion(
626
638
// closure body it could either be type-checked together with the context
627
639
// or not, it's impossible to say without checking.
628
640
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)) {
642
642
// At this point we know the code completion node wasn't checked with
643
643
// the closure's surrounding context, so can defer to regular
644
644
// type-checking for the current call to typeCheckExpression. If that
@@ -651,6 +651,11 @@ bool TypeChecker::typeCheckForCodeCompletion(
651
651
}
652
652
}
653
653
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
+
654
659
llvm::for_each (solutions, callback);
655
660
return CompletionResult::Ok;
656
661
};
0 commit comments