@@ -757,14 +757,48 @@ static void addKeyPathDynamicMemberOverloads(
757
757
}
758
758
}
759
759
760
+ SolutionCompareResult compareSolutionsForCodeCompletion (
761
+ ConstraintSystem &cs, ArrayRef<Solution> solutions, unsigned idx1,
762
+ unsigned idx2) {
763
+
764
+ // When solving for code completion we can't consider one solution worse than
765
+ // another according to the same rules as regular compilation. For example,
766
+ // with the code below:
767
+ //
768
+ // func foo(_ x: Int) -> Int {}
769
+ // func foo<T>(_ x: T) -> String {}
770
+ // foo(3).<complete here> // Still want solutions with for both foo
771
+ // // overloads - String and Int members are both
772
+ // // valid here.
773
+ //
774
+ // the comparison for regular compilation considers the solution with the more
775
+ // specialized `foo` overload `foo(_: Int)` to be better than the solution
776
+ // with the generic overload `foo(_: T)` even though both are otherwise
777
+ // viable. For code completion purposes offering members of 'String' based
778
+ // on the solution with the generic overload is equally as import as offering
779
+ // members of 'Int' as choosing one of those completions will then result in
780
+ // regular compilation resolving the call to the generic overload instead.
781
+
782
+ if (solutions[idx1].getFixedScore () == solutions[idx2].getFixedScore ())
783
+ return SolutionCompareResult::Incomparable;
784
+ return solutions[idx1].getFixedScore () < solutions[idx2].getFixedScore ()
785
+ ? SolutionCompareResult::Better
786
+ : SolutionCompareResult::Worse;
787
+ }
788
+
789
+
760
790
SolutionCompareResult ConstraintSystem::compareSolutions (
761
791
ConstraintSystem &cs, ArrayRef<Solution> solutions,
762
- const SolutionDiff &diff, unsigned idx1, unsigned idx2) {
792
+ const SolutionDiff &diff, unsigned idx1, unsigned idx2,
793
+ bool isForCodeCompletion) {
763
794
if (cs.isDebugMode ()) {
764
795
llvm::errs ().indent (cs.solverState ->depth * 2 )
765
796
<< " comparing solutions " << idx1 << " and " << idx2 <<" \n " ;
766
797
}
767
798
799
+ if (isForCodeCompletion)
800
+ return compareSolutionsForCodeCompletion (cs, solutions, idx1, idx2);
801
+
768
802
// Whether the solutions are identical.
769
803
bool identical = true ;
770
804
@@ -800,7 +834,7 @@ SolutionCompareResult ConstraintSystem::compareSolutions(
800
834
801
835
SmallVector<SolutionDiff::OverloadDiff, 4 > overloadDiff (diff.overloads );
802
836
// Single type of keypath dynamic member lookup could refer to different
803
- // member overlaods , we have to do a pair-wise comparison in such cases
837
+ // member overloads , we have to do a pair-wise comparison in such cases
804
838
// otherwise ranking would miss some viable information e.g.
805
839
// `_ = arr[0..<3]` could refer to subscript through writable or read-only
806
840
// key path and each of them could also pick overload which returns `Slice<T>`
@@ -1300,7 +1334,8 @@ ConstraintSystem::findBestSolution(SmallVectorImpl<Solution> &viable,
1300
1334
SmallVector<bool , 16 > losers (viable.size (), false );
1301
1335
unsigned bestIdx = 0 ;
1302
1336
for (unsigned i = 1 , n = viable.size (); i != n; ++i) {
1303
- switch (compareSolutions (*this , viable, diff, i, bestIdx)) {
1337
+ switch (compareSolutions (*this , viable, diff, i, bestIdx,
1338
+ isForCodeCompletion ())) {
1304
1339
case SolutionCompareResult::Identical:
1305
1340
// FIXME: Might want to warn about this in debug builds, so we can
1306
1341
// find a way to eliminate the redundancy in the search space.
@@ -1324,7 +1359,8 @@ ConstraintSystem::findBestSolution(SmallVectorImpl<Solution> &viable,
1324
1359
if (i == bestIdx)
1325
1360
continue ;
1326
1361
1327
- switch (compareSolutions (*this , viable, diff, bestIdx, i)) {
1362
+ switch (compareSolutions (*this , viable, diff, bestIdx, i,
1363
+ isForCodeCompletion ())) {
1328
1364
case SolutionCompareResult::Identical:
1329
1365
// FIXME: Might want to warn about this in debug builds, so we can
1330
1366
// find a way to eliminate the redundancy in the search space.
@@ -1376,7 +1412,8 @@ ConstraintSystem::findBestSolution(SmallVectorImpl<Solution> &viable,
1376
1412
if (losers[j])
1377
1413
continue ;
1378
1414
1379
- switch (compareSolutions (*this , viable, diff, i, j)) {
1415
+ switch (compareSolutions (*this , viable, diff, i, j,
1416
+ isForCodeCompletion ())) {
1380
1417
case SolutionCompareResult::Identical:
1381
1418
// FIXME: Dub one of these the loser arbitrarily?
1382
1419
break ;
0 commit comments