@@ -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) {
@@ -695,6 +698,29 @@ static void determineBestChoicesInContext(
695
698
fromInitializerCall (fromInitializerCall) {}
696
699
};
697
700
701
+ // Determine whether there are any non-speculative choices
702
+ // in the given set of candidates. Speculative choices are
703
+ // literals or types inferred from initializer calls.
704
+ auto anyNonSpeculativeCandidates =
705
+ [&](ArrayRef<ArgumentCandidate> candidates) {
706
+ // If there is only one (non-CGFloat) candidate inferred from
707
+ // an initializer call we don't consider this a speculation.
708
+ //
709
+ // CGFloat inference is always speculative because of the
710
+ // implicit conversion between Double and CGFloat.
711
+ if (llvm::count_if (candidates, [&](const auto &candidate) {
712
+ return candidate.fromInitializerCall &&
713
+ !candidate.type ->isCGFloat ();
714
+ }) == 1 )
715
+ return true ;
716
+
717
+ // If there are no non-literal and non-initializer-inferred types
718
+ // in the list, consider this is a speculation.
719
+ return llvm::any_of (candidates, [&](const auto &candidate) {
720
+ return !candidate.fromLiteral && !candidate.fromInitializerCall ;
721
+ });
722
+ };
723
+
698
724
SmallVector<SmallVector<ArgumentCandidate, 2 >, 2 >
699
725
argumentCandidates;
700
726
argumentCandidates.resize(argFuncType->getNumParams ());
@@ -819,19 +845,19 @@ static void determineBestChoicesInContext(
819
845
resultTypes.push_back (resultType);
820
846
}
821
847
822
- // Determine whether all of the argument candidates are inferred from literals .
823
- // This information is going to be used later on when we need to decide how to
824
- // score a matching choice.
825
- bool onlyLiteralCandidates =
848
+ // Determine whether all of the argument candidates are speculative (i.e .
849
+ // literals). This information is going to be used later on when we need to
850
+ // decide how to score a matching choice.
851
+ bool onlySpeculativeArgumentCandidates =
826
852
hasArgumentCandidates &&
827
853
llvm::none_of (
828
854
indices (argFuncType->getParams ()), [&](const unsigned argIdx) {
829
- auto &candidates = argumentCandidates[argIdx];
830
- return llvm::any_of (candidates, [&](const auto &candidate) {
831
- return !candidate.fromLiteral ;
832
- });
855
+ return anyNonSpeculativeCandidates (argumentCandidates[argIdx]);
833
856
});
834
857
858
+ bool canUseContextualResultTypes =
859
+ isOperator && !isStandardComparisonOperator(disjunction);
860
+
835
861
// Match arguments to the given overload choice.
836
862
auto matchArguments = [&](OverloadChoice choice, FunctionType *overloadType)
837
863
-> std::optional<MatchCallArgumentResult> {
@@ -1229,16 +1255,12 @@ static void determineBestChoicesInContext(
1229
1255
if (!matchings)
1230
1256
return ;
1231
1257
1232
- auto canUseContextualResultTypes = [&decl]() {
1233
- return decl->isOperator () && !isStandardComparisonOperator (decl);
1234
- };
1235
-
1236
1258
// Require exact matches only if all of the arguments
1237
1259
// are literals and there are no usable contextual result
1238
1260
// types that could help narrow favored choices.
1239
1261
bool favorExactMatchesOnly =
1240
- onlyLiteralCandidates &&
1241
- (!canUseContextualResultTypes () || resultTypes.empty ());
1262
+ onlySpeculativeArgumentCandidates &&
1263
+ (!canUseContextualResultTypes || resultTypes.empty ());
1242
1264
1243
1265
// This is important for SIMD operators in particular because
1244
1266
// a lot of their overloads have same-type requires to a concrete
@@ -1384,7 +1406,7 @@ static void determineBestChoicesInContext(
1384
1406
// because regular functions/methods/subscripts and
1385
1407
// especially initializers could end up with a lot of
1386
1408
// favored overloads because on the result type alone.
1387
- if (canUseContextualResultTypes () &&
1409
+ if (canUseContextualResultTypes &&
1388
1410
(score > 0 || !hasArgumentCandidates)) {
1389
1411
if (llvm::any_of (resultTypes, [&](const Type candidateResultTy) {
1390
1412
return scoreCandidateMatch (genericSig, decl,
@@ -1439,6 +1461,33 @@ static void determineBestChoicesInContext(
1439
1461
info.FavoredChoices .push_back (choice.first );
1440
1462
}
1441
1463
1464
+ // Reset operator disjunction score but keep favoring
1465
+ // choices only available candidates where speculative
1466
+ // with no contextual information available, standard
1467
+ // comparison operators are a special cases because
1468
+ // their return type is fixed to `Bool` unlike that of
1469
+ // bitwise, arithmetic, and other operators.
1470
+ //
1471
+ // This helps to prevent over-eager selection of the
1472
+ // operators over unsupported non-operator declarations.
1473
+ if (isOperator && onlySpeculativeArgumentCandidates &&
1474
+ (!canUseContextualResultTypes || resultTypes.empty())) {
1475
+ if (cs.isDebugMode ()) {
1476
+ PrintOptions PO;
1477
+ PO.PrintTypesForDebugging = true ;
1478
+
1479
+ llvm::errs ().indent (cs.solverState ->getCurrentIndent ())
1480
+ << " <<< Disjunction "
1481
+ << disjunction->getNestedConstraints ()[0 ]
1482
+ ->getFirstType ()
1483
+ ->getString (PO)
1484
+ << " score " << bestScore
1485
+ << " was reset due to having only speculative candidates\n " ;
1486
+ }
1487
+
1488
+ info.Score = 0 ;
1489
+ }
1490
+
1442
1491
recordResult (disjunction, std::move(info));
1443
1492
}
1444
1493
@@ -1604,8 +1653,13 @@ ConstraintSystem::selectDisjunction() {
1604
1653
return *firstScore > *secondScore;
1605
1654
}
1606
1655
1607
- unsigned numFirstFavored = firstFavoredChoices.size ();
1608
- unsigned numSecondFavored = secondFavoredChoices.size ();
1656
+ // Use favored choices only if disjunction score is higher
1657
+ // than zero. This means that we can maintain favoring
1658
+ // choices without impacting selection decisions.
1659
+ unsigned numFirstFavored =
1660
+ firstScore.value_or (0 ) ? firstFavoredChoices.size () : 0 ;
1661
+ unsigned numSecondFavored =
1662
+ secondScore.value_or (0 ) ? secondFavoredChoices.size () : 0 ;
1609
1663
1610
1664
if (numFirstFavored == numSecondFavored) {
1611
1665
if (firstActive != secondActive)
0 commit comments