@@ -108,9 +108,12 @@ static bool isSupportedSpecialConstructor(ConstructorDecl *ctor) {
108
108
return false ;
109
109
}
110
110
111
- static bool isStandardComparisonOperator (ValueDecl *decl) {
112
- return decl->isOperator () &&
113
- decl->getBaseIdentifier ().isStandardComparisonOperator ();
111
+ static bool isStandardComparisonOperator (Constraint *disjunction) {
112
+ auto *choice = disjunction->getNestedConstraints ()[0 ];
113
+ if (auto *decl = getOverloadChoiceDecl (choice))
114
+ return decl->isOperator () &&
115
+ decl->getBaseIdentifier ().isStandardComparisonOperator ();
116
+ return false ;
114
117
}
115
118
116
119
static bool isOperatorNamed (Constraint *disjunction, StringRef name) {
@@ -694,6 +697,38 @@ static void determineBestChoicesInContext(
694
697
fromInitializerCall (fromInitializerCall) {}
695
698
};
696
699
700
+ // Determine whether there are any non-speculative choices
701
+ // in the given set of candidates. Speculative choices are
702
+ // literals or types inferred from initializer calls.
703
+ auto anyNonSpeculativeCandidates =
704
+ [&](ArrayRef<ArgumentCandidate> candidates) {
705
+ // If there is only one (non-CGFloat) candidate inferred from
706
+ // an initializer call we don't consider this a speculation.
707
+ //
708
+ // CGFloat inference is always speculative because of the
709
+ // implicit conversion between Double and CGFloat.
710
+ if (llvm::count_if (candidates, [&](const auto &candidate) {
711
+ return candidate.fromInitializerCall &&
712
+ !candidate.type ->isCGFloat ();
713
+ }) == 1 )
714
+ return true ;
715
+
716
+ // If there are no non-literal and non-initializer-inferred types
717
+ // in the list, consider this is a speculation.
718
+ return llvm::any_of (candidates, [&](const auto &candidate) {
719
+ return !candidate.fromLiteral && !candidate.fromInitializerCall ;
720
+ });
721
+ };
722
+
723
+ auto anyNonSpeculativeResultTypes = [](ArrayRef<Type> results) {
724
+ return llvm::any_of (results, [](Type resultTy) {
725
+ // Double and CGFloat are considered speculative because
726
+ // there exists an implicit conversion between them and
727
+ // preference is based on score impact in the overall solution.
728
+ return !(resultTy->isDouble () || resultTy->isCGFloat ());
729
+ });
730
+ };
731
+
697
732
SmallVector<SmallVector<ArgumentCandidate, 2 >, 2 >
698
733
argumentCandidates;
699
734
argumentCandidates.resize(argFuncType->getNumParams ());
@@ -818,19 +853,19 @@ static void determineBestChoicesInContext(
818
853
resultTypes.push_back (resultType);
819
854
}
820
855
821
- // Determine whether all of the argument candidates are inferred from literals .
822
- // This information is going to be used later on when we need to decide how to
823
- // score a matching choice.
824
- bool onlyLiteralCandidates =
856
+ // Determine whether all of the argument candidates are speculative (i.e .
857
+ // literals). This information is going to be used later on when we need to
858
+ // decide how to score a matching choice.
859
+ bool onlySpeculativeArgumentCandidates =
825
860
hasArgumentCandidates &&
826
861
llvm::none_of (
827
862
indices (argFuncType->getParams ()), [&](const unsigned argIdx) {
828
- auto &candidates = argumentCandidates[argIdx];
829
- return llvm::any_of (candidates, [&](const auto &candidate) {
830
- return !candidate.fromLiteral ;
831
- });
863
+ return anyNonSpeculativeCandidates (argumentCandidates[argIdx]);
832
864
});
833
865
866
+ bool canUseContextualResultTypes =
867
+ isOperator && !isStandardComparisonOperator(disjunction);
868
+
834
869
// Match arguments to the given overload choice.
835
870
auto matchArguments = [&](OverloadChoice choice, FunctionType *overloadType)
836
871
-> std::optional<MatchCallArgumentResult> {
@@ -1229,16 +1264,12 @@ static void determineBestChoicesInContext(
1229
1264
if (!matchings)
1230
1265
return ;
1231
1266
1232
- auto canUseContextualResultTypes = [&decl]() {
1233
- return decl->isOperator () && !isStandardComparisonOperator (decl);
1234
- };
1235
-
1236
1267
// Require exact matches only if all of the arguments
1237
1268
// are literals and there are no usable contextual result
1238
1269
// types that could help narrow favored choices.
1239
1270
bool favorExactMatchesOnly =
1240
- onlyLiteralCandidates &&
1241
- (!canUseContextualResultTypes () || resultTypes.empty ());
1271
+ onlySpeculativeArgumentCandidates &&
1272
+ (!canUseContextualResultTypes || resultTypes.empty ());
1242
1273
1243
1274
// This is important for SIMD operators in particular because
1244
1275
// a lot of their overloads have same-type requires to a concrete
@@ -1384,7 +1415,7 @@ static void determineBestChoicesInContext(
1384
1415
// because regular functions/methods/subscripts and
1385
1416
// especially initializers could end up with a lot of
1386
1417
// favored overloads because on the result type alone.
1387
- if (canUseContextualResultTypes () &&
1418
+ if (canUseContextualResultTypes &&
1388
1419
(score > 0 || !hasArgumentCandidates)) {
1389
1420
if (llvm::any_of (resultTypes, [&](const Type candidateResultTy) {
1390
1421
return scoreCandidateMatch (genericSig, decl,
@@ -1439,6 +1470,34 @@ static void determineBestChoicesInContext(
1439
1470
info.FavoredChoices .push_back (choice.first );
1440
1471
}
1441
1472
1473
+ // Reset operator disjunction score but keep favoring
1474
+ // choices only available candidates where speculative
1475
+ // with no contextual information available, standard
1476
+ // comparison operators are a special cases because
1477
+ // their return type is fixed to `Bool` unlike that of
1478
+ // bitwise, arithmetic, and other operators.
1479
+ //
1480
+ // This helps to prevent over-eager selection of the
1481
+ // operators over unsupported non-operator declarations.
1482
+ if (isOperator && onlySpeculativeArgumentCandidates &&
1483
+ (!canUseContextualResultTypes ||
1484
+ !anyNonSpeculativeResultTypes(resultTypes))) {
1485
+ if (cs.isDebugMode ()) {
1486
+ PrintOptions PO;
1487
+ PO.PrintTypesForDebugging = true ;
1488
+
1489
+ llvm::errs ().indent (cs.solverState ->getCurrentIndent ())
1490
+ << " <<< Disjunction "
1491
+ << disjunction->getNestedConstraints ()[0 ]
1492
+ ->getFirstType ()
1493
+ ->getString (PO)
1494
+ << " score " << bestScore
1495
+ << " was reset due to having only speculative candidates\n " ;
1496
+ }
1497
+
1498
+ info.Score = 0 ;
1499
+ }
1500
+
1442
1501
recordResult (disjunction, std::move(info));
1443
1502
}
1444
1503
@@ -1610,8 +1669,13 @@ ConstraintSystem::selectDisjunction() {
1610
1669
return *firstScore > *secondScore;
1611
1670
}
1612
1671
1613
- unsigned numFirstFavored = firstFavoredChoices.size ();
1614
- unsigned numSecondFavored = secondFavoredChoices.size ();
1672
+ // Use favored choices only if disjunction score is higher
1673
+ // than zero. This means that we can maintain favoring
1674
+ // choices without impacting selection decisions.
1675
+ unsigned numFirstFavored =
1676
+ firstScore.value_or (0 ) ? firstFavoredChoices.size () : 0 ;
1677
+ unsigned numSecondFavored =
1678
+ secondScore.value_or (0 ) ? secondFavoredChoices.size () : 0 ;
1615
1679
1616
1680
if (numFirstFavored == numSecondFavored) {
1617
1681
if (firstActive != secondActive)
0 commit comments