|
15 | 15 | //===----------------------------------------------------------------------===//
|
16 | 16 |
|
17 | 17 | #include "TypeChecker.h"
|
| 18 | +#include "OpenedExistentials.h" |
18 | 19 | #include "swift/AST/ConformanceLookup.h"
|
19 | 20 | #include "swift/AST/ExistentialLayout.h"
|
20 | 21 | #include "swift/AST/GenericSignature.h"
|
@@ -1197,18 +1198,20 @@ static void determineBestChoicesInContext(
|
1197 | 1198 | // - Superclass conversion
|
1198 | 1199 | // - Array-to-pointer conversion
|
1199 | 1200 | // - Value to existential conversion
|
| 1201 | + // - Existential opening |
1200 | 1202 | // - Exact match on top-level types
|
1201 | 1203 | //
|
1202 | 1204 | // In situations when it's not possible to determine whether a candidate
|
1203 | 1205 | // type matches a parameter type (i.e. when partially resolved generic
|
1204 | 1206 | // types are matched) this function is going to produce \c std::nullopt
|
1205 | 1207 | // instead of `0` that indicates "not a match".
|
1206 |
| - std::function<std::optional<double>(GenericSignature, ValueDecl *, Type, |
1207 |
| - Type, MatchOptions)> |
| 1208 | + std::function<std::optional<double>(GenericSignature, ValueDecl *, |
| 1209 | + std::optional<unsigned>, Type, Type, |
| 1210 | + MatchOptions)> |
1208 | 1211 | scoreCandidateMatch =
|
1209 | 1212 | [&](GenericSignature genericSig, ValueDecl *choice,
|
1210 |
| - Type candidateType, Type paramType, |
1211 |
| - MatchOptions options) -> std::optional<double> { |
| 1213 | + std::optional<unsigned> paramIdx, Type candidateType, |
| 1214 | + Type paramType, MatchOptions options) -> std::optional<double> { |
1212 | 1215 | auto areEqual = [&](Type a, Type b) {
|
1213 | 1216 | return a->getDesugaredType()->isEqual(b->getDesugaredType());
|
1214 | 1217 | };
|
@@ -1260,7 +1263,7 @@ static void determineBestChoicesInContext(
|
1260 | 1263 | // This helps to determine whether there are any generic
|
1261 | 1264 | // overloads that are a possible match.
|
1262 | 1265 | auto score =
|
1263 |
| - scoreCandidateMatch(genericSig, choice, candidateType, |
| 1266 | + scoreCandidateMatch(genericSig, choice, paramIdx, candidateType, |
1264 | 1267 | paramType, options - MatchFlag::Literal);
|
1265 | 1268 | if (score == 0)
|
1266 | 1269 | return 0;
|
@@ -1347,8 +1350,8 @@ static void determineBestChoicesInContext(
|
1347 | 1350 | if ((paramOptionals.empty() &&
|
1348 | 1351 | paramType->is<GenericTypeParamType>()) ||
|
1349 | 1352 | paramOptionals.size() >= candidateOptionals.size()) {
|
1350 |
| - auto score = scoreCandidateMatch(genericSig, choice, candidateType, |
1351 |
| - paramType, options); |
| 1353 | + auto score = scoreCandidateMatch(genericSig, choice, paramIdx, |
| 1354 | + candidateType, paramType, options); |
1352 | 1355 |
|
1353 | 1356 | if (score > 0) {
|
1354 | 1357 | // Injection lowers the score slightly to comply with
|
@@ -1394,6 +1397,21 @@ static void determineBestChoicesInContext(
|
1394 | 1397 | if (paramType->isAny())
|
1395 | 1398 | return 1;
|
1396 | 1399 |
|
| 1400 | + // Check if a candidate could be matched to a parameter by |
| 1401 | + // an existential opening. |
| 1402 | + if (options.contains(MatchFlag::OnParam) && |
| 1403 | + candidateType->getMetatypeInstanceType()->isExistentialType()) { |
| 1404 | + if (auto *genericParam = paramType->getMetatypeInstanceType() |
| 1405 | + ->getAs<GenericTypeParamType>()) { |
| 1406 | + if (canOpenExistentialAt(choice, *paramIdx, genericParam, |
| 1407 | + candidateType->getMetatypeInstanceType())) { |
| 1408 | + // Lower the score slightly for operators to make sure that |
| 1409 | + // concrete overloads are always preferred over generic ones. |
| 1410 | + return choice->isOperator() ? 0.9 : 1; |
| 1411 | + } |
| 1412 | + } |
| 1413 | + } |
| 1414 | + |
1397 | 1415 | // Check protocol requirement(s) if this parameter is a
|
1398 | 1416 | // generic parameter type.
|
1399 | 1417 | if (genericSig && paramType->isTypeParameter()) {
|
@@ -1661,9 +1679,10 @@ static void determineBestChoicesInContext(
|
1661 | 1679 | options |= MatchFlag::StringInterpolation;
|
1662 | 1680 |
|
1663 | 1681 | // The specifier for a candidate only matters for `inout` check.
|
1664 |
| - auto candidateScore = scoreCandidateMatch( |
1665 |
| - genericSig, decl, candidate.type->getWithoutSpecifierType(), |
1666 |
| - paramType, options); |
| 1682 | + auto candidateScore = |
| 1683 | + scoreCandidateMatch(genericSig, decl, paramIdx, |
| 1684 | + candidate.type->getWithoutSpecifierType(), |
| 1685 | + paramType, options); |
1667 | 1686 |
|
1668 | 1687 | if (!candidateScore)
|
1669 | 1688 | continue;
|
@@ -1706,6 +1725,7 @@ static void determineBestChoicesInContext(
|
1706 | 1725 | (score > 0 || !hasArgumentCandidates)) {
|
1707 | 1726 | if (llvm::any_of(resultTypes, [&](const Type candidateResultTy) {
|
1708 | 1727 | return scoreCandidateMatch(genericSig, decl,
|
| 1728 | + /*paramIdx=*/std::nullopt, |
1709 | 1729 | overloadType->getResult(),
|
1710 | 1730 | candidateResultTy,
|
1711 | 1731 | /*options=*/{}) > 0;
|
|
0 commit comments